views:

273

answers:

7

Hi everyone, Is there a reasonable explanation, why searching an element in Java collection is so hard? For example, let's say I have:

ArrayList<People> listPeople = new ArrayList<People>();

public class People
{
   public String name;
   public String age;
   //some other code here
}

You got the idea ... Now, if I want to get from list a Person with given name, let's say 'Anthares' I have to do so much work: Create a new Person with name 'Anthares', probably initiate it with some other data, predefine my equals method for Person class, then call listPeople.IndexOf(tempPerson) and finally get the returned int and make listPeople[idx]

Why is all this pain. For example, in C# I can make a linq expression, pass it to the proper method of my collection and that's it. One simple line of code.

A: 

If you want to search, you should use HashMap/HashTable and hash on a person's name.

If you implement linq in Java, you won't need to :)

DVK
+2  A: 
for(Person p : listPeople) {
  if(p.name.equals("Anthares")) {
    found = p;
    break;
  }
}

You'll likely be able to do it pretty much like in C# with jdk7.

nos
scheduled for release in September 2010: http://openjdk.java.net/projects/jdk7/calendar/
Adam Bernier
+5  A: 

No you don't - you can do:

Person found = null;
for (Person person : listPeople)
{
    if ("Anthares".equals(person.name))
    {
        found = person;
        break;
    }
}
// Check for found == null etc

Yes, it's still more work than LINQ, but that's basically because C# has closures in the form of lambda expressions. You could implement something similar in Java if you were willing to write:

Person person = FakeLinq.findFirst(listPeople, new Predicate<Person>() {
    @Override boolean matches(Person person) {
        return person.name.equals("Anthares");
    }
});

Most of the conciseness of the C# solution is just allowing you to express that predicate very simply.

Java 7 will (hopefully!) have something reasonably similar to lambda expressions, at which point this becomes feasible in Java too.

Jon Skeet
FakeLinq looks an awful lot like Apache Commons CollectionUtils.
Paul Tomblin
@Paul: I strongly suspect there's something similar in the Google Java Collections (or Guava) too. The point of the answer was to comment on which bits are to do with the language and which are to do with libraries.
Jon Skeet
Yes there is something similar in Guava: `Iterables.find(Iterable, Predicate)`. But I would rather use `Multimaps.index(Iterable, Function)` to create an auxilliary map indexed on the `name` field.
finnw
+3  A: 

Look at the Apache Commons collection api, specifically CollectionUtils.find

Paul Tomblin
A: 

You could just use an iterator and then compare the name field to the name you are searching for (all of which just involves using the Java API)

Also, a HashMap would probably be a much better data structure to use seeing as how you are using name as a "key" in this example.

The problem isn't with java collections, its with your choice of data structure/implementation.

CheesePls
+1  A: 

In my humble opinion, they made one silly mistake in the Java collections classes that complicates the problem. When you do a Collection.indexOf(want), they search the collection saying, basically "if (want.equals(collectionMember))" rather than "if (collectionMember.equals(want))".

I think the latter would have been better, because it would have enabled you to simply write a "MyObject.equals(String)" function or "MyObject.equals(Integer)", i.e. compare your custom object to a general object. Then you could implement it as, say ...

public boolean equals(String wantname)
{
  return this.name.equals(wantname);
}

But because it's actually implemented as "if (want.equals(collectionMember))", of course the Java String class doesn't have an "equals(MyObject)" function, so you can't just give it a string to search for. Instead, you have to create a dummy object to hold the value you want to find.

Yeah, as others posters have indicated, it's not a big deal to write a quick function to search a collection sequentially. But what if we're talking about a collection where a sequential search is not practical or efficient, like a HashMap or tree structure?

Jay
This behavior, though it's not part of the specification, was intentional. How much more experienced are you than all the people who built that library, that you can just declare it a "silly mistake"?
Kevin Bourrillion
What was I thinking! I humbly abase myself for my impertinence in daring to question the all-wise, all-knowing creators of Java! Seriously now, I like to think I'm a smart guy -- if you want credentials I have 30 years in the business and I wrote a book on database design -- but I don't have to suppose that I'm smarter than James Gosling et al to question them. I'm sure all of us have written code and later looked back at it and said, "Oops, that was a poor design decision." Besides, I have the advantage of hindsight. I'd be happy to hear any reasons you can offer why this was a GOOD decision?
Jay
A: 

With lambdaj you can achieve that result as easily as it follows:

select(listPeople, having(on(Person.class).getName(), equalTo("Anthares"))
Mario Fusco