从 Java 列表结构中选择基数最低的元素

Choose elements with lowest cardinality from Java List structure

一个简单的问题,但在 google 上找不到答案。因为我通常使用 SQL,所以我习惯于像这样访问基于集合的操作:

select Q, qCount
from (
  select Q, qCount, min(qCount) over () as minQCount
  from (
    select Q, count(*) as qCount
    from table_A
    group by Q
  ) 
)
where qCount = minQCount

这会从 table 中找到所有 Q 值,这些值在一组不同的 Q 值中具有最低的基数。

对于 Java 列表,是否有既定的有效方法?说:

List<Q> listOfQ //gets populated with different objects of Q
//objects of Q can represent the same value through an overridden equals()
//get each object from Q for which the cardinality of the value it represents 
//is the lowest amongst the distinct values in the list

一个简单的例子是:

List<Integer> list = new ArrayList<Integer>(); 
list.addAll(Arrays.asList(new Integer[] {1,1,1,2,2,3,3,3,4,4,4,4,5,5}));
//want to retrieve {2,2,5,5}
//would also be nice to easily retrieve a map with {k:2 v:2, k:5 v:2} 
//this being the equivalent of the SQL query above

谢谢!

Hashtable<String, Integer> ht = new Hashtable<String, Integer>() ; 
for(Integer i : list){
    if(ht.contain(i+""){
          Integer v = ht.get(i+"") + 1 ; 
    }else{
         ht.put(i+"" , 1) ; 
    }
}

// now we need order it 
TreeMap<String, Integer> tm= new TreeMap<Integer, String>(ht);

现在树图将按键和值排序

考虑使用 GUAVA 的 Multiset

上面可以用count(key)方法得到号码

private static <K> Map<K, Integer> getElementsWithLessCardinality(
        List<K> list) {
    Map<K, Integer> map = new TreeMap<K, Integer>(); //or HashMap
    Map<K, Integer> res = new TreeMap<K, Integer>();
    Integer min = null;
    for (K listElem : list) {
        if (map.containsKey(listElem)) {
            map.put(listElem, map.get(listElem) + 1);
        } else {
            map.put(listElem, 1);
        }
    }

    for (Entry<K, Integer> pair : map.entrySet()) {
        K key = pair.getKey();
        Integer value = pair.getValue();
        if (min == null) {
            // Initial state
            min = value;
            res.put(key, value);
        } else if (min.equals(pair.getValue())) {
            res.put(key, value);
        } else if (value.compareTo(min) == -1) {
            res.clear();
            min = value;
            res.put(key, value);
        }
    }

    return res;
}

我想你可以这样做:

-首先你得到一张完整的地图。

-然后你找基数小的放到另外一个map里。

请注意,此解决方案使用参数类型,因此您可以在需要计算任何类型的对象时使用它。 (但要确保 compareTo()、equals() 和 hashCode() 在 class K 中得到很好的实现)

使用 apache 公共集合:

  final List<Integer> list = Arrays.asList(new Integer[]{1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5});
  final Map<Integer, Integer> cardinalityMap = CollectionUtils.getCardinalityMap(list);
  final int minCardinality = Collections.min(cardinalityMap.values());
  System.out.println("min cardinality: " + minCardinality);
  for (final Map.Entry<Integer, Integer> entry: cardinalityMap.entrySet()) {
    if (minCardinality == entry.getValue()) {
      System.out.println("key: " + entry.getKey());
    }
  }

控制台输出:

min cardinality: 2
key: 2
key: 5