Java方法:在给定已知属性值的数组列表中查找对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/739192/
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 method: Finding object in array list given a known attribute value
提问by Northener
I have a couple of questions actually.
我实际上有几个问题。
I have a class Dogwith the following instance fields:
我有一个带有以下实例字段的类Dog:
private int id;
private int id_mother;
private int id_father;
private String name="";
private String owner="";
private String bDate="";
I also have a class Archivewhich can instantiate Dogand put Dog objects into an ArrayList.
我还有一个Archive类,它可以实例化Dog并将 Dog 对象放入一个 ArrayList 中。
I am trying to write a method in Archivewhich takes an integer as ID and looks through the ArrayList, and returns the object containing that ID.
我正在尝试在Archive 中编写一个方法,该方法将整数作为 ID 并查看 ArrayList,并返回包含该 ID 的对象。
private Dog getDog(int id){
Dog dog = new Dog();
int length=getSize();
int i=0;
dog=al.get(i);
i++;
while(dog.getId()!=id && i<length)
dog=al.get(i);
i++;
if(dog.getId()!=id)
dog=null;
return dog;
}//end getDog
There are two problems with this method (the other methods I use work). First of all it's not working, and I can't see why. I'm while-looping through (potentially) all the objects in the arraylist, for then after the loop is finished, checking whether the loop finished because it ran out of objects to search through, or because it found an object with the given ID. Secondly, that seems like an immensely time-consuming process. Is there some way to speed this up?
这种方法有两个问题(我使用的其他方法有效)。首先它不起作用,我不明白为什么。我正在循环遍历(可能)arraylist 中的所有对象,然后在循环完成后,检查循环是否完成是因为它用完了要搜索的对象,或者因为它找到了具有给定 ID 的对象. 其次,这似乎是一个非常耗时的过程。有什么方法可以加快速度吗?
采纳答案by tpdi
A while
applies to the expression or block after the while
.
Awhile
适用于 之后的表达式或块while
。
You dont have a block, so your while ends with the expression dog=al.get(i);
你没有一个块,所以你的 while 以表达式结束 dog=al.get(i);
while(dog.getId()!=id && i<length)
dog=al.get(i);
Everything after that happens only once.
之后的一切只发生一次。
There's no reason to new up a Dog, as you're never using the dog you new'd up; you immediately assign a Dog from the array to your dog reference.
没有理由养一只狗,因为你从来没有用过你养的狗;您立即将数组中的 Dog 分配给您的 dog 引用。
And if you need to get a value for a key, you should use a Map, not an Array.
如果需要获取键的值,则应使用 Map,而不是 Array。
Edit: this was donwmodded why??
编辑:这是donwmodded为什么?
Comment from OP:
来自 OP 的评论:
One further question with regards to not having to make a new instance of a Dog. If I am just taking out copies of the objects from the array list, how can I then take it out from the array list without having an object in which I put it? I just noticed as well that I didn't bracket the while-loop.
关于不必制作新的 Dog 实例的另一个问题。如果我只是从数组列表中取出对象的副本,那么如何在没有放置对象的情况下从数组列表中取出它?我也注意到我没有将 while 循环括起来。
A Java reference and the object it refers to are different things. They're very much like a C++ reference and object, though a Java reference can be re-pointed like a C++ pointer.
Java 引用和它引用的对象是不同的东西。它们非常像 C++ 引用和对象,尽管 Java 引用可以像 C++ 指针一样重新指向。
The upshot is that Dog dog;
or Dog dog = null
gives you a reference that points to no object. new Dog()
createsan object that can be pointed to.
结果是Dog dog;
orDog dog = null
给你一个不指向任何对象的引用。new Dog()
创建一个可以指向的对象。
Following that with a dog = al.get(i)
means that the reference now points to the dog reference returned by al.get(i)
. Understand, in Java, objects are never returned, only references to objects (which are addresses of the object in memory).
紧随其后的是 adog = al.get(i)
意味着该引用现在指向由 返回的 dog 引用al.get(i)
。了解,在 Java 中,永远不会返回对象,只返回对对象的引用(即对象在内存中的地址)。
The pointer/reference/address of the Dog you newed up is now lost, as no code refers to it, as the referent was replaced with the referent you got from al.get()
. Eventually the Java garbage collector will destroy that object; in C++ you'd have "leaked" the memory.
你新创建的 Dog 的指针/引用/地址现在丢失了,因为没有代码引用它,因为引用对象被你从al.get()
. 最终 Java 垃圾收集器将销毁该对象;在 C++ 中,你会“泄露”内存。
The upshot is that you do need to create a variable that can refer to a Dog; you don't need to create a Dog with new
.
结果是您确实需要创建一个可以引用 Dog 的变量;你不需要用new
.
(In truth you don't need to create a reference, as what you really ought to be doing is returning what a Map returns from its get() function. If the Map isn't parametrized on Dog, like this: Map<Dog>
, then you'll need to cast the return from get, but you won't need a reference: return (Dog) map.get(id);
or if the Map is parameterized, return map.get(id)
. And that one line is your whole function, and it'll be faster than iterating an array for most cases.)
(实际上,您不需要创建引用,因为您真正应该做的是返回 Map 从其 get() 函数返回的内容。如果 Map 未在 Dog 上参数化,例如:Map<Dog>
,那么您' 将需要从 get 转换返回,但您不需要引用:return (Dog) map.get(id);
或者如果 Map 被参数化,则return map.get(id)
该行是您的整个函数,并且在大多数情况下它比迭代数组更快。 )
回答by Jorn
You have to loop through the entire array, there's no changing that. You can however, do it a little easier
你必须遍历整个数组,没有改变。但是,您可以稍微轻松一点
for (Dog dog : list) {
if (dog.getId() == id) {
return dog; //gotcha!
}
}
return null; // dog not found.
or without the new for loop
或者没有新的 for 循环
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getId() == id) {
return list.get(i);
}
}
回答by Rob
To improve performance of the operation, if you're always going to want to look up objects by some unique identifier, then you might consider using a Map<Integer,Dog>
. This will provide constant-time lookup by key. You can still iterate over the objects themselves using the map values()
.
为了提高操作的性能,如果您总是希望通过某个唯一标识符查找对象,那么您可以考虑使用Map<Integer,Dog>
. 这将通过键提供恒定时间查找。您仍然可以使用 map 迭代对象本身values()
。
A quick code fragment to get you started:
一个快速的代码片段让你开始:
// Populate the map
Map<Integer,Dog> dogs = new HashMap<Integer,Dog>();
for( Dog dog : /* dog source */ ) {
dogs.put( dog.getId(), dog );
}
// Perform a lookup
Dog dog = dogs.get( id );
This will help speed things up a bit if you're performing multiple lookups of the same nature on the list. If you're just doing the one lookup, then you're going to incur the same loop overhead regardless.
如果您在列表上执行多个相同性质的查找,这将有助于加快速度。如果您只是进行一次查找,那么无论如何您都会产生相同的循环开销。
回答by Tom Hawtin - tackline
I was interested to see that the original poster used a style that avoided early exits. Single Entry; Single Exit (SESE) is an interesting style that I've not really explored. It's late and I've got a bottle of cider, so I've written a solution (not tested) without an early exit.
我很感兴趣地看到原始海报使用了一种避免提前退出的风格。单次入境;Single Exit (SESE) 是一种有趣的风格,我还没有真正探索过。很晚了,我有一瓶苹果酒,所以我写了一个没有提前退出的解决方案(未经测试)。
I should have used an iterator. Unfortunately java.util.Iterator
has a side-effect in the get method. (I don't like the Iterator
design due to its exception ramifications.)
我应该使用迭代器。不幸的是java.util.Iterator
,get 方法有副作用。(Iterator
由于其异常后果,我不喜欢该设计。)
private Dog findDog(int id) {
int i = 0;
for (; i!=dogs.length() && dogs.get(i).getID()!=id; ++i) {
;
}
return i!=dogs.length() ? dogs.get(i) : null;
}
Note the duplication of the i!=dogs.length()
expression (could have chosen dogs.get(i).getID()!=id
).
注意i!=dogs.length()
表达式的重复(可以选择dogs.get(i).getID()!=id
)。
回答by Jon
Assuming that you've written an equals method for Dog correctly that compares based on the id of the Dog the easiest and simplest way to return an item in the list is as follows.
假设您已经为 Dog 正确编写了一个 equals 方法,该方法根据 Dog 的 id 进行比较,返回列表中项目的最简单和最简单的方法如下。
if (dogList.contains(dog)) {
return dogList.get(dogList.indexOf(dog));
}
That's less performance intensive that other approaches here. You don't need a loop at all in this case. Hope this helps.
与此处的其他方法相比,这对性能的要求较低。在这种情况下,您根本不需要循环。希望这可以帮助。
P.S You can use Apache Commons Lang to write a simple equals method for Dog as follows:
PS可以使用Apache Commons Lang为Dog写一个简单的equals方法如下:
@Override
public boolean equals(Object obj) {
EqualsBuilder builder = new EqualsBuilder().append(this.getId(), obj.getId());
return builder.isEquals();
}
回答by Seth
If you have to get an attribute that is not the ID. I would use CollectionUtils.
如果您必须获取不是 ID 的属性。我会使用CollectionUtils。
Dog someDog = new Dog();
Dog dog = CollectionUtils(dogList, new Predicate() {
@Override
public boolean evaluate(Object o)
{
Dog d = (Dog)o;
return someDog.getName().equals(d.getName());
}
});
回答by Federico Traiman
I solved this using java 8 lambdas
我使用 java 8 lambdas 解决了这个问题
int dogId = 2;
return dogList.stream().filter(dog-> dogId == dog.getId()).collect(Collectors.toList()).get(0);
回答by anson
List<YourClass> list = ArrayList<YourClass>();
List<String> userNames = list.stream().map(m -> m.getUserName()).collect(Collectors.toList());
output: ["John","Alex"]
输出:[“约翰”,“亚历克斯”]