我有List<Custom>
列表Custom
就像
class Custom{
public int id;
public String name;
}
如何获取名称为“Tom”的项目数量?是否比for循环更简单?
答案 0 :(得分:11)
现在可以使用Java 8流轻松完成 - 无需额外的库。
List<Custom> list = /*...*/;
long numMatches = list.stream()
.filter(c -> "Tom".equals(c.name))
.count();
答案 1 :(得分:5)
如果要在多个位置按名称进行过滤,特别是如果要将该过滤器与运行时确定的其他过滤器链接起来,Google Guava谓词可能会对您有所帮助:
public static Predicate<Custom> nameIs(final String name) {
return new Predicate<Custom>() {
@Override public boolean apply(Custom t) {
return t.name.equals(name);
}
};
}
一旦编码了该谓词,过滤和计数只需要一行代码。
int size = Collections2.filter(customList, nameIs("Tom")).size();
正如您所看到的,与循环(命令式样式)相比,谓词(函数式)的冗长构造并不总是更易读,更快或者保存代码行。实际上,Guava documentation明确指出默认情况下应该使用命令式样式。但谓词无论如何都是一个很好的工具。
答案 2 :(得分:4)
就我个人而言,我喜欢使用Apache Commons Collection lib。 (但是因为它使用了泛型,所以在sourceforge上的那个)它可以让你做一些非常优雅的事情,比如映射列表或过滤列表(以方案方式)。你最终会写这样的东西:
int count = CollectionUtils.countMatches(myList, new Predicate<Custom>(){
public boolean evaluate(Custom c){ return "Tom".equals(c.name); }
}
唯一的缺点是,由于Java没有一阶函数,你必须编写像Predicate实例这样的小对象。如果你能写匿名函数会更干净。即在斯卡拉,就是这样:
val myList = List("a", "a", "b", "c", "a")
val c = myList.count{ "a".equals(_) } // is 3
答案 3 :(得分:2)
标准集合没有更简单的解决方案。您必须遍历列表并计算名称的出现次数。
答案 4 :(得分:1)
您可以在添加或删除列表中的项目时进行跟踪。这可以取代hashmap Name-&gt; Count。当你添加一个项目时,你增加该名称的计数,当你删除它时,你减少计数。
或者您通过循环检查有问题的名称来迭代集合。
根据应用程序的行为,其中一种方法会更快,但如果没有更多信息,则很难分辨出哪种方法。
答案 5 :(得分:1)
可能更容易。 现在,您可以将对象存储在Map&lt; String,List&lt; Custom&gt;&gt;而是密钥是名称的地方。 要获得name ==“Tom”的项目数,您可以简单地执行:
List<Custom> l = myMap.get("Tom");
int count = 0;
if (l != null) {
count = l.size();
}
答案 6 :(得分:1)
您也可以在循环之前对列表进行排序,然后使用“分而治之”来查找匹配项,然后计算。这真的取决于你的需求,比如有多少元素?搜索后有很多插入吗?等
答案 7 :(得分:1)
现在定义它的方式总是需要在列表上循环。
使用名称映射创建辅助索引到ids列表是一个好主意。
另一个选择是确保列表按名称排序,在这种情况下,所有“Tom”将彼此相邻存储。然后你可以在O(log(n))时间内用二进制搜索找到第一个“Tom”,然后从那里继续计数,直到你到达非“Tom”或列表的末尾。插入操作将具有O(n)复杂度,因为您需要将插入位置之后的所有元素移动一个位置,因此请仔细考虑: - )
答案 8 :(得分:0)
这个怎么样? :
package test;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class CustomArrayBuilder extends ArrayList<Custom> {
Map<String, Integer> namesMap = new HashMap<String, Integer>();
public CustomArrayBuilder(Collection<? extends Custom> 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<? extends Custom> c) {
this.prepareAddAll(c);
return super.addAll(c);
}
/**
* {@inheritDoc}
*/
@Override
public boolean addAll(int index, Collection<? extends Custom> 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<? extends Custom> 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<Custom> list = new ArrayList<Custom>() {{
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对象的名称时,您也必须对列表执行某些操作。
答案 9 :(得分:0)
您可以使用Eclipse Collections中的count()
。
MutableList<Custom> customList = Lists.mutable.empty();
int count = customList.count(each -> "Tom".equals(each.getName()));
如果您无法从List
更改customList:
List<Custom> customList = new ArrayList<>();
int count = ListAdapter.adapt(customList).count(each -> "Tom".equals(each.getName()));
如果您有检查名称的方法,也可以使用countWith()
:
MutableList<Custom> 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的撰稿人。