下面是到目前为止我尝试过的代码,它可以正常工作:
public static void main(String[] args) {
Random random = new Random();
Integer[] integers = random.ints(10, 100, 999).boxed().toArray(Integer[]::new);
List<Integer> list = new ArrayList<>();
for (int i = 0; i < integers.length; i++) {
String[] split = integers[i].toString().split("");
int a = 0, b = 0, c = 0;
a = Integer.valueOf(split[0]);
b = Integer.valueOf(split[1]);
c = Integer.valueOf(split[2]);
if ((a != b) && (a != c) && (b != c)) {
list.add(Integer.valueOf(integers[i]));
}
}
list.forEach(System.out::println);
}
输出正确。
如果 abc 是整数,则
a !=b
和a ! c
和b !=c
, 使所有数字唯一。
我尝试在流中应用后面的部分,但没有得到预期的结果。有人可以指导我我要去哪里了吗?
Java-8版本:
public static void main(String[] args) {
Random random = new Random();
Integer[] integers = random.ints(10, 100, 999).boxed().toArray(Integer[]::new);
String[] collect = Arrays.stream(integers).map(s -> {
String[] split = s.toString().split("");
return split;
}).filter(
k -> (Integer.valueOf(k[0]) != Integer.valueOf(k[1])) && (Integer.valueOf(k[0]) != Integer
.valueOf(k[2])) && (Integer.valueOf(k[1]) != Integer.valueOf(k[2])))
.toArray(String [] ::new);
Arrays.stream(collect).forEach(System.out::println);
}
答案 0 :(得分:6)
将数字转换为字符串并调用split("")
可能会最慢您可能想到的解决方案。
如果您有一个3位数字,并且想要3位数字,请使用除法和余数运算符:
int i = /*assign some non-negative number of at most 3 digits*/;
int d1 = i / 100;
int d2 = i / 10 % 10;
int d3 = i % 10;
如果您需要N
个数字,则无法生成N
个数字,然后丢弃其中的一些数字。这样会使您更少少于N
数字。您必须先算出 后再丢弃错误的数字。
static int[] generate(int n) {
// Numbers 100 and 101 contain duplicates, so lower limit is 102.
// Upper limit is 987 (inclusive), since 988, 989, and 99x all contain duplicates.
return new Random().ints(102, 988)
.filter(Test::isThreeUniqueDigits)
.limit(n)
.toArray();
}
private static boolean isThreeUniqueDigits(int i) {
int d1 = i / 100;
int d2 = i / 10 % 10;
int d3 = i % 10;
return (d1 != d2 && d1 != d3 && d2 != d3);
}
或者使用lambda表达式代替方法参考:
static int[] generate(int n) {
return new Random().ints(102, 988).filter(i -> {
int d1 = i / 100, d2 = i / 10 % 10, d3 = i % 10;
return (d1 != d2 && d1 != d3 && d2 != d3);
}).limit(n).toArray();
}
样本结果
[416, 613, 401, 250, 507, 306, 179, 152, 850, 504]
[913, 304, 174, 874, 714, 245, 632, 890, 357, 382]
[618, 706, 946, 364, 209, 320, 690, 529, 824, 651]
[419, 386, 547, 471, 952, 917, 389, 469, 640, 285]
[120, 347, 549, 247, 619, 328, 814, 240, 984, 630]
[127, 174, 723, 287, 149, 329, 176, 964, 451, 617]
[539, 587, 768, 594, 296, 948, 157, 409, 952, 395]
[602, 392, 698, 761, 231, 764, 517, 147, 402, 841]
[194, 294, 923, 542, 362, 248, 352, 286, 407, 348]
[631, 502, 461, 439, 174, 278, 407, 394, 617, 370]
[754, 193, 539, 290, 504, 684, 921, 962, 724, 196]
[125, 586, 925, 857, 879, 761, 134, 620, 134, 723]
[457, 307, 524, 536, 249, 349, 901, 623, 247, 320]
[103, 903, 506, 645, 431, 802, 695, 761, 609, 867]
[569, 894, 608, 963, 681, 365, 162, 874, 452, 307]
[807, 178, 983, 837, 956, 273, 295, 527, 798, 406]
[157, 936, 398, 379, 618, 920, 957, 921, 430, 879]
[396, 280, 315, 569, 328, 138, 931, 623, 413, 926]
[987, 972, 518, 391, 138, 691, 372, 193, 402, 678]
[346, 328, 940, 768, 307, 419, 146, 950, 671, 530]
答案 1 :(得分:4)
您正在分割字符串,然后不合并分割数组。
在.map(strings -> String.join("", strings))
之前添加.toArray(String [] ::new);
以解决问题。
答案 2 :(得分:3)
一个方面未得到处理:结果中出现重复的数字。
一个人也可以将结果收集到一个具有唯一编号的集合中。 我使用了LinkedHashSet,它按生成的数字顺序保留生成的数字, 没有专门按照HashSet(按hashCode排序)或TreeSet(按顺序)排序。
然后,由于重复项需要更多尝试,因此无法使用随机整数列表。
您的算法将变为:
// Maximal different numbers 9*9*8 as different digits 10*9*8 and first digit not 0.
final int MAX_N = 9*9*8; // 648
int size = N;
if (size > MAX_N) {
throw new IllegalArgumentException("More than maximum " + MAX_N + ": " + size);
}
Set<Integer> result = new LinkedHashSet<Integer>();
Random random = new Random();
for (int i = 0; i < size; ++i) {
int n = randomUnique(random);
if (!result.add(n)) {
--i; // Already added, take a new random int.
// When size nears MAX_N the looping take enormous long!
}
}
System.out.println(result);
但是可以立即正确选择随机的唯一数字:
static int randomUnique(Random random) {
// 1-9
int d2 = 1 + random.nextInt(9);
int n = d2;
// 0-9 without d1
int d1 = random.nextInt(9); // As index in those digits.
if (d1 >= d2) {
++d1;
}
n = 10 * n + d1;
// 0-9 without d1 and d2
int d0 = random.nextInt(8); // As index in those digits.
if (d0 >= d1 || d0 >= d2) {
++d0;
if (d0 >= d1 && d0 >= d2) {
++d0;
}
}
n = 10 * n + d0;
return n;
}
如前所述,该算法将在大小接近MAX_N时尝试大量的randomUnique调用。
更好的方法是取100-999之间的所有数字,然后随机取一个合适大小的子集。
这似乎是一种困惑,是家庭作业,只是一些指向更好,通常更快的算法的指针:
BitSet uniqueNumbers = new BitSet(1000);
for (int num = 100; num < 1000; ++num) {
uniqueNumbers.set(num, isUnique(num));
}
... take N elements
boolean isUnique(int num) {
...
}
答案 3 :(得分:2)
您可以首先生成有效数字,而不是生成随机数字来测试它们并丢弃无效的数字。
只需逐位生成它们。第一个在数百个位置,必须在1…9范围内且没有其他限制,因此我们可以直接生成它。第二个必须在0…9范围内,但不能等于第一个,因此我们可以在1…9范围内生成一个数字,如果等于第一个,则将其替换为零。同样,最后一个位置的数字在2…9范围内生成,如果等于第一个数字,则替换为零;如果等于第二个数字,则替换为一个。然后,我们有一个有效的号码,无需重复该过程。
作为一个简单的循环,看起来像
if(N > 648) throw new IllegalArgumentException("There can't be "+N+" unique numbers");
ThreadLocalRandom r = ThreadLocalRandom.current();
Set<Integer> result = new LinkedHashSet<>(N);
while(result.size() < N) {
int hundreds = r.nextInt(1, 10);
int tens = r.nextInt(1, 10);
if(tens == hundreds) tens = 0;
int ones = r.nextInt(2, 10);
if(ones == hundreds) ones = 0;
if(ones == tens) ones = 1;
result.add(hundreds * 100 + tens * 10 + ones);
}
通过使用Set
并测试大小而不是使用计数循环,我们确保生成N
唯一编号。
或者,我们可以先创建一个所有有效数字的可重用列表,然后将任务更改为“从列表中选择N个项目”,也可以在其他情况下重用。
生成所有有效数字很简单,遍历所有数字然后跳过无效的数字,然后计算该数字,这比遍历所有数字并测试它们要简单,而这需要昂贵的数字提取。
List<Integer> validNumbers = new ArrayList<>();
for(int h = 1; h < 10; h++) {
for(int t = 0; t < 10; t++) {
if(t == h) continue;
for(int o = 0; o < 10; o++) {
if(o != t && o != h) validNumbers.add(h * 100 + t * 10 + o);
}
}
}
然后,我们可以选择N
个唯一元素:
if(N > validNumbers.size()) throw new IllegalArgumentException();
// copying, so validNumbers can be reused
List<Integer> result = new ArrayList<>(validNumbers);
if(N == result.size()) {
Collections.shuffle(result);
}
else {
for (int i = 0; i < N; i++) {
Collections.swap(result, i, r.nextInt(i, result.size()));
}
result.subList(N, result.size()).clear();
}
第一个分支,当N == validNumbers.size()
时,我们只需要对数字进行混洗并具有N
个有效的随机元素。当N
较小时,替代方法基本上与shuffle
在内部相同,但是省略了我们未选择的元素的工作,最后删除了它们。
我们可以使用Stream API表达相同的逻辑,但这并不总是成功。
第一个变体可能是
List<Integer> result = IntStream.generate(() -> {
ThreadLocalRandom r = ThreadLocalRandom.current();
int h = r.nextInt(1, 10), t = r.nextInt(1, 10), o = r.nextInt(2, 10);
if(t == h) t = 0;
if(o == h) o = 0;
if(o == t) o = 1;
return h * 100 + t * 10 + o;
})
.distinct().limit(N).boxed()
.collect(Collectors.toList());
如果.boxed().collect(Collectors.toList())
数组结果足够,则可以将toArray()
替换为int[]
。
对于第二种方法,我们可以使用
int[] validNumbers = IntStream.range(1, 10)
.flatMap(h -> IntStream.range(0, 10).filter(t -> t != h)
.flatMap(t -> IntStream.range(0, 10).filter(o -> o != t && o != h)
.map(o -> h * 100 + t * 10 + o)))
.toArray();
获取有效数字和
List<Integer> result = ThreadLocalRandom.current()
.ints(0, validNumbers.length)
.distinct().limit(N)
.mapToObj(ix -> validNumbers[ix])
.collect(Collectors.toList());
选择N
个不同的元素(可能比shuffle
方法更昂贵)。同样,当数组.mapToObj(ix -> validNumbers[ix]) .collect(Collectors.toList())
足够时,可以用.map(ix -> validNumbers[ix]) .toArray()
替换int[]
。