Java List.contains(字段值等于x的对象)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18852059/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java List.contains(Object with field value equal to x)
提问by Rudi Kershaw
I want to check whether a List
contains an object that has a field with a certain value. Now, I could use a loop to go through and check, but I was curious if there was anything more code efficient.
我想检查 a 是否List
包含具有特定值的字段的对象。现在,我可以使用循环来进行检查,但我很好奇是否有更高效的代码。
Something like;
就像是;
if(list.contains(new Object().setName("John"))){
//Do some stuff
}
I know the above code doesn't do anything, it's just to demonstrate roughly what I am trying to achieve.
我知道上面的代码没有做任何事情,它只是为了大致演示我想要实现的目标。
Also, just to clarify, the reason I don't want to use a simple loop is because this code will currently go inside a loop that is inside a loop which is inside a loop. For readability I don't want to keep adding loops to these loops. So I wondered if there were any simple(ish) alternatives.
另外,为了澄清一下,我不想使用简单循环的原因是因为此代码当前将进入一个位于循环内的循环内。为了可读性,我不想继续向这些循环添加循环。所以我想知道是否有任何简单的(ish)替代品。
采纳答案by Josh M
Streams
流
If you are using Java 8, perhaps you could try something like this:
如果您使用的是 Java 8,也许您可以尝试这样的操作:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().filter(o -> o.getName().equals(name)).findFirst().isPresent();
}
Or alternatively, you could try something like this:
或者,你可以尝试这样的事情:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().map(MyObject::getName).filter(name::equals).findFirst().isPresent();
}
This method will return true
if the List<MyObject>
contains a MyObject
with the name name
. If you want to perform an operation on each of the MyObject
s that getName().equals(name)
, then you could try something like this:
true
如果List<MyObject>
包含MyObject
名称为 的,则此方法将返回name
。如果您想对每个MyObject
s that执行操作getName().equals(name)
,那么您可以尝试这样的操作:
public void perform(final List<MyObject> list, final String name){
list.stream().filter(o -> o.getName().equals(name)).forEach(
o -> {
//...
}
);
}
Where o
represents a MyObject
instance.
其中o
代表一个MyObject
实例。
Alternatively, as the comments suggest (Thanks MK10), you could use the Stream#anyMatch
method:
或者,正如评论所建议的(感谢 MK10),您可以使用以下Stream#anyMatch
方法:
public boolean containsName(final List<MyObject> list, final String name){
return list.stream().anyMatch(o -> o.getName().equals(name));
}
回答by Juned Ahsan
contains
method uses equals
internally. So you need to override the equals
method for your class as per your need.
contains
方法equals
内部使用。因此,您需要根据需要覆盖equals
类的方法。
Btw this does not look syntatically correct:
顺便说一句,这在语法上看起来不正确:
new Object().setName("John")
回答by Brian Agnew
Google Guava
谷歌番石榴
If you're using Guava, you can take a functional approach and do the following
如果您使用的是Guava,则可以采用函数式方法并执行以下操作
FluentIterable.from(list).find(new Predicate<MyObject>() {
public boolean apply(MyObject input) {
return "John".equals(input.getName());
}
}).Any();
which looks a little verbose. However the predicate is an object and you can provide different variants for different searches. Note how the library itself separates the iteration of the collection and the function you wish to apply. You don't have to override equals()
for a particular behaviour.
这看起来有点冗长。然而,谓词是一个对象,您可以为不同的搜索提供不同的变体。请注意库本身如何将集合的迭代与您希望应用的函数分开。您不必覆盖equals()
特定行为。
As noted below, the java.util.Streamframework built into Java 8 and later provides something similar.
如下所述,Java 8 及更高版本中内置的java.util.Stream框架提供了类似的功能。
回答by Aaron Digulla
Collection.contains()
is implemented by calling equals()
on each object until one returns true
.
Collection.contains()
是通过调用equals()
每个对象直到一个对象返回来实现的true
。
So one way to implement this is to override equals()
but of course, you can only have one equals.
所以实现这一点的一种方法是覆盖,equals()
但当然,你只能有一个等于。
Frameworks like Guavatherefore use predicates for this. With Iterables.find(list, predicate)
, you can search for arbitrary fields by putting the test into the predicate.
因此,像Guava这样的框架为此使用谓词。使用Iterables.find(list, predicate)
,您可以通过将测试放入谓词来搜索任意字段。
Other languages built on top of the VM have this built in. In Groovy, for example, you simply write:
构建在 VM 之上的其他语言都内置了这一点。例如,在Groovy 中,您只需编写:
def result = list.find{ it.name == 'John' }
Java 8 made all our lives easier, too:
Java 8 也让我们的生活变得更轻松:
List<Foo> result = list.stream()
.filter(it -> "John".equals(it.getName())
.collect(Collectors.toList());
If you care about things like this, I suggest the book "Beyond Java". It contains many examples for the numerous shortcomings of Java and how other languages do better.
如果你关心这样的事情,我推荐“Beyond Java”这本书。它包含许多示例,说明 Java 的众多缺点以及其他语言如何做得更好。
回答by Debojit Saikia
Binary Search
二分查找
You can use Collections.binarySearchto search an element in your list (assuming the list is sorted):
您可以使用Collections.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());
}
});
which will return a negative number if the object is not present in the collection or else it will return the index
of the object. With this you can search for objects with different searching strategies.
如果对象不存在于集合中,它将返回一个负数,否则它将返回index
对象的 。有了它,您可以使用不同的搜索策略搜索对象。
回答by James Dunn
You have two choices.
你有两个选择。
1. The first choice, which is preferable, is to override the `equals()` method in your Object class.
1. 第一种选择,最好是覆盖 Object 类中的 `equals()` 方法。
Let's say, for example, you have this Object class:
例如,假设您有这个 Object 类:
public class MyObject {
private String name;
private String location;
//getters and setters
}
Now let's say you only care about the MyObject's name, that it should be unique so if two `MyObject`s have the same name they should be considered equal. In that case, you would want to override the `equals()` method (and also the `hashcode()` method) so that it compares the names to determine equality.
现在假设您只关心 MyObject 的名称,它应该是唯一的,因此如果两个 `MyObject` 具有相同的名称,它们应该被认为是相等的。在这种情况下,您可能希望覆盖 `equals()` 方法(以及 `hashcode()` 方法),以便它比较名称以确定相等性。
Once you've done this, you can check to see if a Collection contains a MyObject with the name "foo" by like so:
完成此操作后,您可以通过如下方式检查集合是否包含名为“foo”的 MyObject:
MyObject object = new MyObject();
object.setName("foo");
collection.contains(object);
However, this might not be an option for you if:
但是,如果出现以下情况,这可能不适合您:
- You are using both the name and location to check for equality, but you only want to check if a Collection has any `MyObject`s with a certain location. In this case, you've already overridden `equals()`.
- `MyObject` is part of an API that you don't have liberty to change.
- 您同时使用名称和位置来检查相等性,但您只想检查集合是否有任何具有特定位置的“MyObject”。在这种情况下,您已经覆盖了 `equals()`。
- `MyObject` 是 API 的一部分,您无权更改。
If either of these are the case, you'll want option 2:
如果是其中任何一种情况,您将需要选项 2:
2. Write your own utility method:
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;
}
Alternatively, you could extend ArrayList (or some other collection) and then add your own method to it:
或者,您可以扩展 ArrayList(或其他一些集合),然后向其中添加您自己的方法:
public boolean containsLocation(String location) {
for(MyObject o : this) {
if(o != null && o.getLocation.equals(location)) {
return true;
}
}
return false;
}
Unfortunately there's not a better way around it.
不幸的是,没有更好的方法来解决它。
回答by Craig P. Motlin
Eclipse Collections
日食系列
If you're using Eclipse Collections, you can use the anySatisfy()
method. Either adapt your List
in a ListAdapter
or change your List
into a ListIterable
if possible.
如果您使用的是Eclipse Collections,则可以使用该anySatisfy()
方法。如果可能的话,要么适应你List
的 aListAdapter
要么改变你的。List
ListIterable
ListIterable<MyObject> list = ...;
boolean result =
list.anySatisfy(myObject -> myObject.getName().equals("John"));
If you'll do operations like this frequently, it's better to extract a method which answers whether the type has the attribute.
如果你经常做这样的操作,最好提取一个方法来回答类型是否有属性。
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);
}
}
You can use the alternate form anySatisfyWith()
together with a method reference.
您可以将替代形式anySatisfyWith()
与方法引用一起使用。
boolean result = list.anySatisfyWith(MyObject::named, "John");
If you cannot change your List
into a ListIterable
, here's how you'd use ListAdapter
.
如果您不能将您的更改List
为 a ListIterable
,那么您将如何使用ListAdapter
.
boolean result =
ListAdapter.adapt(list).anySatisfyWith(MyObject::named, "John");
Note: I am a committer for Eclipse ollections.
注意:我是 Eclipse ollections 的提交者。
回答by Magda
If you need to perform this List.contains(Object with field value equal to x)
repeatedly, a simple and efficient workaround would be:
如果您需要List.contains(Object with field value equal to x)
重复执行此操作,一个简单有效的解决方法是:
List<field obj type> fieldOfInterestValues = new ArrayList<field obj type>;
for(Object obj : List) {
fieldOfInterestValues.add(obj.getFieldOfInterest());
}
Then the List.contains(Object with field value equal to x)
would be have the same result as fieldOfInterestValues.contains(x);
那么List.contains(Object with field value equal to x)
结果将与fieldOfInterestValues.contains(x);
回答by user902383
Predicate
Predicate
If you dont use Java 8, or library which gives you more functionality for dealing with collections, you could implement something which can be more reusable than your solution.
如果您不使用 Java 8 或为您提供更多处理集合功能的库,您可以实现一些比您的解决方案更可重用的东西。
interface Predicate<T>{
boolean contains(T item);
}
static class CollectionUtil{
public static <T> T find(final Collection<T> collection,final Predicate<T> predicate){
for (T item : collection){
if (predicate.contains(item)){
return item;
}
}
return null;
}
// and many more methods to deal with collection
}
i'm using something like that, i have predicate interface, and i'm passing it implementation to my util class.
我正在使用类似的东西,我有谓词接口,我将它的实现传递给我的 util 类。
What is advantage of doing this in my way? you have one method which deals with searching in any type collection. and you dont have to create separate methods if you want to search by different field. alll what you need to do is provide different predicate which can be destroyed as soon as it no longer usefull/
以我的方式这样做有什么好处?您有一种方法可以处理在任何类型集合中进行搜索。如果您想按不同的字段进行搜索,则不必创建单独的方法。您需要做的就是提供不同的谓词,一旦它不再有用,就可以将其销毁/
if you want to use it, all what you need to do is call method and define tyour predicate
如果你想使用它,你需要做的就是调用方法并定义你的谓词
CollectionUtil.find(list, new Predicate<MyObject>{
public boolean contains(T item){
return "John".equals(item.getName());
}
});
回答by user902383
Map
地图
You could create a Hashmap<String, Object>
using one of the values as a key, and then seeing if yourHashMap.keySet().contains(yourValue)
returns true.
您可以Hashmap<String, Object>
使用其中一个值作为键创建一个,然后查看是否yourHashMap.keySet().contains(yourValue)
返回 true。