我想检查一个列表是否包含一个对象,该对象具有具有特定值的字段。现在,我可以使用循环来遍历和检查,但我很好奇是否有更高效的代码。
类似的;
if(list.contains(new Object().setName("John"))){
//Do some stuff
}
我知道上面的代码没有做任何事情,它只是粗略地演示了我想要实现的目标。
另外,澄清一下,我不想使用简单循环的原因是,这段代码将进入一个循环,这个循环在一个循环中,而这个循环又在一个循环中。为了可读性,我不想一直在这些循环中添加循环。所以我想知道是否有什么简单的替代方案。
Eclipse集合
如果您正在使用Eclipse Collections,则可以使用anyssatisfy()方法。如果可能的话,在ListAdapter中调整列表或将列表更改为ListIterable。
ListIterable<MyObject> list = ...;
boolean result =
list.anySatisfy(myObject -> myObject.getName().equals("John"));
如果要经常执行这样的操作,最好提取一个方法来回答该类型是否具有该属性。
public class MyObject
{
private final String name;
public MyObject(String name)
{
this.name = name;
}
public boolean named(String name)
{
return Objects.equals(this.name, name);
}
}
您可以使用替代形式anySatisfyWith()和方法引用。
boolean result = list.anySatisfyWith(MyObject::named, "John");
如果不能将List更改为ListIterable,下面是如何使用ListAdapter。
boolean result =
ListAdapter.adapt(list).anySatisfyWith(MyObject::named, "John");
注意:我是Eclipse集合的提交者。
二分查找
您可以使用集合。binarySearch用于搜索列表中的元素(假设列表是有序的):
Collections.binarySearch(list, new YourObject("a1", "b",
"c"), new Comparator<YourObject>() {
@Override
public int compare(YourObject o1, YourObject o2) {
return o1.getName().compareTo(o2.getName());
}
});
如果该对象不存在于集合中,它将返回一个负数,否则将返回该对象的索引。有了它,您可以使用不同的搜索策略搜索对象。
流
如果你正在使用Java 8,也许你可以尝试这样做:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().filter(o -> o.getName().equals(name)).findFirst().isPresent();
}
或者,你可以尝试这样做:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().map(MyObject::getName).filter(name::equals).findFirst().isPresent();
}
如果List<MyObject>包含名称为name的MyObject,此方法将返回true。如果你想对getName().equals(name)的每个myobject执行一个操作,那么你可以尝试这样做:
public void perform(final List<MyObject> list, final String name){
list.stream().filter(o -> o.getName().equals(name)).forEach(
o -> {
//...
}
);
}
其中o表示MyObject实例。
或者,正如评论所建议的(感谢MK10),你可以使用Stream#anyMatch方法:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().anyMatch(o -> name.equals(o.getName()));
}
你有两个选择。
1. 首选的方法是重写Object类中的' equals() '方法。
比方说,你有这样一个Object类:
public class MyObject {
private String name;
private String location;
//getters and setters
}
现在我们假设你只关心MyObject的名字,它应该是唯一的,所以如果两个MyObject有相同的名字它们应该被认为是相等的。在这种情况下,您可能希望重写' equals() '方法(以及' hashcode() '方法),以便它比较名称以确定是否相等。
一旦你这样做了,你可以检查一个集合是否包含一个名为“foo”的MyObject,就像这样:
MyObject object = new MyObject();
object.setName("foo");
collection.contains(object);
但是,在以下情况下,这可能不适合你:
您同时使用名称和位置来检查是否相等,但您只想检查集合中是否有具有特定位置的' MyObject '。在本例中,您已经重写了' equals() '。
MyObject是API的一部分你没有自由去改变它。
如果是这两种情况,你需要选择2:
2. 编写自己的实用方法:
public static boolean containsLocation(Collection<MyObject> c, String location) {
for(MyObject o : c) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
或者,你可以扩展ArrayList(或其他集合),然后添加你自己的方法:
public boolean containsLocation(String location) {
for(MyObject o : this) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
不幸的是,没有更好的办法了。