Reputation: 3664
I have a List of Foo Objects. If a name appears multiple times, I want to do something to the first Item with that name.
HashMap<String, Foo> map = new HashMap<String, Foo>();
for (Foo bar: this.FooList)
{
if (!map.containsKey(bar.getName()))
{
map.put(bar.getName(), bar);
}
else
{
map.get(bar.getName()).doSomeThing();
}
}
But this is not working, because every name (unique or not) gets thrown in that map. Does the HashMap check only for reference equality and not equality on key objects?
Upvotes: 1
Views: 7395
Reputation: 71929
What exactly is the problem? The code adds the Foo
if it hasn't been encountered before, and invokes an action on the Foo
if it has been encountered before. What were you expecting it to do?
To answer your question at the end, HashMap
relies on the hashCode
and equals
methods of the key objects.
UPDATE: Are you trying to invoke doSomeThing
only on repeated Foo
s? If the name
property of a Foo
defines it's identity (and you properly implemented hashCode()
and equals()
) you should use R. Bemrose's solution. If name
is not a unique property of Foo
s, the following code might help:
final Map<String, Foo> firstFooByName = new HashMap<String, Foo>();
final List<String> dupeNames = new ArrayList<String>();
for (final Foo foo: myFoos) {
final String fooName = foo.getName();
if (!firstFooByName.containsKey(fooName)) {
firstFooByName.add(fooName)
} else {
dupeNames.add(fooName);
}
}
for (final String fooName : dupeNames) {
firstFooByName.get(fooName).doSomeThing();
}
Upvotes: 0
Reputation: 88786
Hmmm... if Foo implements equals()
so that it only checks name, you could always do something like this:
Set<Foo> set = new HashSet<Foo>();
for (Foo bar: this.FooList)
{
if (!set.add(bar)) {
bar.doSomething();
}
}
Which works because set.add(bar)
will run bar.equals
against every element already in the set, and return false if any of them are equal.
Edit: Since this is a HashSet, you should also implement hashCode()
. Heck, you should always implement hashCode()
if you're overriding equals
anyway.
Upvotes: 1
Reputation: 837886
This is the code you need:
HashMap<String, Foo> map = new HashMap<String, Foo>();
for (Foo bar: this.FooList)
{
if (!map.containsKey(bar.getName()))
{
map.put(bar.getName(), bar);
}
else
{
Foo foo = map.get(bar.getName());
if (foo != null)
foo.doSomeThing();
map.put(bar.getName(), null);
}
}
Here's a testbed for it:
import java.util.HashMap;
import java.util.ArrayList;
public class Example
{
public static void main(String[] args)
{
new Example().run();
}
private ArrayList<Foo> FooList = new ArrayList<Foo>();
public void run()
{
FooList.add(new Foo("abc", 1));
FooList.add(new Foo("abc", 2));
FooList.add(new Foo("def", 3));
FooList.add(new Foo("abc", 4));
FooList.add(new Foo("abc", 5));
FooList.add(new Foo("ghi", 6));
FooList.add(new Foo("def", 7));
HashMap<String, Foo> map = new HashMap<String, Foo>();
for (Foo bar: this.FooList)
{
if (!map.containsKey(bar.getName()))
{
map.put(bar.getName(), bar);
}
else
{
Foo foo = map.get(bar.getName());
if (foo != null)
foo.doSomeThing();
map.put(bar.getName(), null);
}
}
}
class Foo
{
public Foo(String name, int i)
{
this.name = name;
this.i = i;
}
public String getName()
{
return name;
}
public void doSomeThing()
{
System.out.println(getName() + " " + i);
}
private String name;
private int i;
}
}
Output is:
abc 1
def 3
Upvotes: 3