计算具有财产的物品数量

我有列表List ,其中Custom就像

 class Custom{ public int id; public String name; } 

如何获得名称为“Tom”的项目数量? 有没有比for循环更简单的方法?

现在可以使用Java 8流轻松完成 – 无需额外的库。

 List list = /*...*/; long numMatches = list.stream() .filter(c -> "Tom".equals(c.name)) .count(); 

如果您要在多个位置按名称进行过滤,特别是如果要将其filter与其他在运行时确定的filter链接, Google Guava谓词可能会帮助您:

 public static Predicate nameIs(final String name) { return new Predicate() { @Override public boolean apply(Custom t) { return t.name.equals(name); } }; } 

一旦编码了该谓词,过滤和计数将只需要一行代码。

 int size = Collections2.filter(customList, nameIs("Tom")).size(); 

正如您所看到的,与循环(命令式样式)相比,谓词(函数式)的冗长构造并不总是更易读,更快或者保存代码行。 实际上, Guava文档明确指出默认情况下应该使用命令式样式。 但是谓词无论如何都是一个很好的工具。

就个人而言,我喜欢使用Apache Commons Collection lib。 (但是因为它使用了generics,所以在sourceforge上的那个)它可以让你做一些非常优雅的事情,比如映射列表或过滤列表(以方案方式)。 你最终会写这样的东西:

 int count = CollectionUtils.countMatches(myList, new Predicate(){ public boolean evaluate(Custom c){ return "Tom".equals(c.name); } } 

唯一的缺点是,由于Java没有一阶函数,你必须编写像Predicate实例这样的小对象。 如果你能写匿名函数会更干净。 即在scala中,它将是这样的:

 val myList = List("a", "a", "b", "c", "a") val c = myList.count{ "a".equals(_) } // is 3 

标准集合没有更简单的解决方案。 您必须迭代列表并计算名称的出现次数。

您可以在添加或删除列表中的项目时进行跟踪。 这可以取代hashmap Name-> Count。 在您添加项目的位置时,您会增加该名称的计数,当您删除它时,您会减少计数。

或者您通过循环检查有问题的名称来迭代集合。

根据您的应用程序的行为,这些方法之一将更快,但没有更多信息,很难分辨哪些方法。

更容易,可能不是。 现在,您可以将对象存储在Map >中,而不是键是名称。 要获取name ==“Tom”的项目数,您可以简单地执行以下操作:

 List l = myMap.get("Tom"); int count = 0; if (l != null) { count = l.size(); } 

您也可以在循环之前对列表进行排序,然后使用“分而治之”来查找匹配项,然后计算。 这真的取决于你的需求,比如有多少元素? 搜索后有很多插入吗? 等等

现在定义它的方式总是需要在列表上循环。

使用名称映射创建二级索引到一个id列表是一个好主意。

还有一个选择是确保列表按名称排序,在这种情况下,所有“Tom”将彼此相邻存储。 然后你可以在O(log(n))时间内用二进制搜索找到拳头“Tom”,并从那里继续计数,直到你到达非“Tom”或列表的末尾。 插入操作将具有O(n)复杂度,因为您需要将插入位置之后的所有元素移动一个位置,因此请仔细考虑:-)

那这个呢? :

 package test; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; public class CustomArrayBuilder extends ArrayList { Map namesMap = new HashMap(); public CustomArrayBuilder(Collection c) { super(c); this.prepareAddAll(c); } public int getDifferentNamesAmount() { return this.namesMap.size(); } public int getNameAmount(String name) { Integer integer = this.namesMap.get(name); return (integer != null) ? integer : 0; } /** * {@inheritDoc} */ @Override public Custom set(int index, Custom element) { Custom custom = super.set(index, element); prepareSet(custom, element); return custom; } /** * {@inheritDoc} */ @Override public boolean add(Custom e) { this.prepareAdd(e); return super.add(e); } /** * {@inheritDoc} */ @Override public void add(int index, Custom element) { this.prepareAdd(element); super.add(index, element); } /** * {@inheritDoc} */ @Override public Custom remove(int index) { Custom custom = super.remove(index); this.prepareRemove(custom); return custom; } /** * {@inheritDoc} */ @Override public void clear() { super.clear(); this.namesMap.clear(); } /** * {@inheritDoc} */ @Override public boolean addAll(Collection c) { this.prepareAddAll(c); return super.addAll(c); } /** * {@inheritDoc} */ @Override public boolean addAll(int index, Collection c) { this.prepareAddAll(c); return super.addAll(index, c); } /** * {@inheritDoc} */ @Override public boolean remove(Object o) { if (super.remove(o)) { this.prepareRemove((Custom) o); return true; } else { return false; } } private void prepareSet(Custom oldCustom, Custom newCustom) { if (oldCustom != null && !oldCustom.name.equals(newCustom.name)) { this.prepareRemove(oldCustom); this.prepareAdd(newCustom); } } private void prepareAdd(Custom custom) { if (custom != null) { Integer integer = this.namesMap.get(custom.name); this.namesMap.put(custom.name, (integer != null) ? integer + 1 : 1); } } private void prepareAddAll(Collection c) { for (Custom custom : c) { this.prepareAdd(custom); } } private void prepareRemove(Custom custom) { if (custom != null) { Integer integer = this.namesMap.get(custom.name); this.namesMap.put(custom.name, (integer != null && integer > 0) ? integer - 1 : 0); } } } 

用法:

 package test; import java.util.ArrayList; import java.util.List; public class Test { public static void main(String[] args) { List list = new ArrayList() {{ add(new Custom("A")); add(new Custom("B")); add(new Custom("C")); add(new Custom("A")); add(new Custom("A")); add(new Custom("B")); }}; CustomArrayBuilder customs = new CustomArrayBuilder(list); Custom custom = new Custom("B"); customs.add(custom); customs.add(custom); customs.remove(custom); customs.remove(custom); customs.remove(custom); System.out.println("A: " + customs.getNameAmount("A")); System.out.println("B: " + customs.getNameAmount("B")); System.out.println("C: " + customs.getNameAmount("C")); System.out.println("Z: " + customs.getNameAmount("Z")); System.out.println("Total different names: " + customs.getDifferentNamesAmount()); } } 

输出:

 A: 3 B: 2 C: 1 Z: 0 Total different names: 3 

当您经常使用计数操作时,它可能很有用。 注意:您不应该更改自定义对象的名称,它应该是最终的:

 package test; class Custom { public int id; final public String name; public Custom(String name) { this.name = name; } } 

或者,当您从列表中更改某些Custom对象的名称时,您也必须对列表执行某些操作。

您可以使用Eclipse Collections中的 count()

 MutableList customList = Lists.mutable.empty(); int count = customList.count(each -> "Tom".equals(each.getName())); 

如果您无法从List更改customList:

 List customList = new ArrayList<>(); int count = ListAdapter.adapt(customList).count(each -> "Tom".equals(each.getName())); 

如果你有一个检查名称的方法,你也可以使用countWith()

 MutableList customList = Lists.mutable.empty(); int count = customList.countWith(Custom::isNamed, "Tom"); class Custom { public int id; public String name; public boolean isNamed(String nameToCheck) { return nameToCheck.equals(this.name); } } 

注意:我是Eclipse Collections的贡献者。