2015-04-30 53 views
2

一个简单的问题与最低基数的元素,但无法找到对谷歌的答案。因为通常我用SQL的工作,我已经习惯了有机会获得基于集合的操作是这样的:选择从Java列表结构

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 

此发现从具有最低基数跻身组不同的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 

谢谢!

+0

“基数”是Java的一个奇特的词。谷歌“计数事件”或“频率”,你会有更多的运气。相关SO问题:http://stackoverflow.com/questions/14260134/elegant-way-of-counting-occurrences-in-a-java-collection –

回答

1

使用Apache Commons Collections中:

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 
+0

这是很多final,yikes –

-1
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); 

现在树图将被排序键和值

+0

这个实现的几个问题:不需要将键转换为'String' ;只需将它们保留为“对象”或通用参数化类型即可。新代码应该避免使用'Hashtable'来支持'HashMap'。并且'新的TreeMap (Hashtable )'由于类型不匹配和可能的键冲突而必然失败。 –

+0

首先,我试图展示如何解决这个问题,而不是试图完成代码的运行,其他字符串是你最好的选择,因为它提供了出色的哈希代码和相同的实现。是的,TreeMap必须是

1
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; 
} 

拿到号码,我想你可以做这样的事情:

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

- 然后找到基数较少的地方并放入另一张地图。

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