首页 > 解决方案 > 如何计算java中的唯一值

问题描述

我想计算数组中唯一值的数量,但我无法以正确的方式计算。

int uniqueNumbers = 1;
Arrays.sort(n);

if (n.length == 0) {
    uniqueNumbers = 0;
}

for ( int i = 1; i < n.length; i++) {
    if (n[i] != n[i - 1]) {
        uniqueNumbers++;
    }
}

问题是,如果一个整数出现多次,它仍然算作一个唯一的数字,而我不希望它被算作一个唯一的数字。

标签: javaarrayscompare

解决方案


用于跟踪唯一编号并丢弃它的嵌套循环可以帮助解决此任务:

public static int countUnique(int ... n) {
    Arrays.sort(n);
    
    System.out.println(Arrays.toString(n));

    int uniqueNumbers = 0;

    for (int i = 0; i < n.length; i++) {
        boolean unique = true;
        for (int j = i + 1; j < n.length && n[i] == n[j]; j++, i++) {
            unique = false;
        }
        if (unique) {
            uniqueNumbers++;
        }
    }
    return uniqueNumbers;
}

测试:

System.out.println(countUnique(2, 1, 2, 3, 4, 6, 4));
System.out.println(countUnique(2, 1, 2, 3, 4, 1, 4));
System.out.println(countUnique(2, 1, 2, 4, 4, 1, 4));

输出:

[1, 2, 2, 3, 4, 4, 6]
3
[1, 1, 2, 2, 3, 4, 4]
1
[1, 1, 2, 2, 4, 4, 4]
0

然而,由于对输入数组进行排序,该算法的复杂度为O(N log N).


如果允许使用集合中已经存在元素时返回Set的事实来跟踪重复项,则可以如下实现(另外,输入数组不需要排序,因此该算法具有复杂性):Set::addfalseO(N)

public static int countUniqueSets(int ... n) {
    System.out.println(Arrays.toString(n));
    
    Set<Integer> ones = new HashSet<>();
    Set<Integer> dups = new HashSet<>();
    
    for (int x : n) {
        if (!ones.add(x)) {
            dups.add(x);
        }
    }
    System.out.println("distinct: " + ones);
    System.out.println("duplicates: " + dups);

    return ones.size() - dups.size();
}

相同测试的输出:

[2, 1, 2, 3, 4, 6, 4]
distinct: [1, 2, 3, 4, 6]
duplicates: [2, 4]
3
[2, 1, 2, 3, 4, 1, 4]
distinct: [1, 2, 3, 4]
duplicates: [1, 2, 4]
1
[2, 1, 2, 4, 4, 1, 4]
distinct: [1, 2, 4]
duplicates: [1, 2, 4]
0

使用 Stream API 的另一种方法是使用Collectors.groupingBy+Collectors.counting或构建频率图Collectors.summingInt,然后使用 计算图中的条目frequency = 1

public static int countUniqueStream(int ... n) {
    System.out.println(Arrays.toString(n));
    
    return (int) Arrays.stream(n)
                 .boxed()
                 .collect(Collectors.groupingBy(
                     x -> x,
                     Collectors.counting()
                 )) // Map<Integer, Long>
                 .entrySet()
                 .stream()
                 .filter(e -> 1 == e.getValue())
                 .count();
}

public static int countUniqueStreamInt(int ... n) {
    System.out.println(Arrays.toString(n));
    
    return Arrays.stream(n)
                 .boxed()
                 .collect(Collectors.groupingBy(
                    x -> x,
                    Collectors.summingInt(x -> 1)
                 ))  // Map<Integer, Integer>
                 .entrySet().stream()
                 .filter(e -> 1 == e.getValue())
                 .collect(Collectors.summingInt(e -> 1));
}

推荐阅读