Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

An interchangeable key/value HashMap Set structure

Background

Create a series of SQL JOIN statements using two operands: primary and secondary. The generic form of the JOIN statement is:

JOIN primary primary ON (secondary.id == primary.id)

Problem

The code currently iterates over a list of primary and secondary operands, as follows:

for( Bundle primaryOperand : bundleComparators ) {
  for( Bundle secondaryOperand : sortedBundles ) {

The problem is that the nested loop generates the following:

JOIN primary primary ON (secondary.id == primary.id)
JOIN secondary secondary ON (primary.id == secondary.id)

The second join is superfluous and, in this case, causes an error. The duplication can be eliminated with the following hypothetical data structure:

if( !interchangeableMap.contains( primaryOperand, secondaryOperand ) ) {
    interchangeableMap.put( primaryOperand, secondaryOperand );

    outputJoin( primaryOperand, secondaryOperand );
}

Where interchangeableMap.contains(...) will return true if primaryOperand is mapped to secondaryOperand or secondaryOperand is mapped to primaryOperand.

Questions

  1. Does such a data structure exist in the Java libraries?
  2. If not, what data structures would you use for its implementation?

Ideas

My first thought is to create a class that contains two HashMaps. Checking for containment queries the two HashMaps to see if one map contains the primary and secondary operands or the other map contains the secondary and primary operands. Insertions put the two operand combinations into their respective HashMaps.

Thank you!

like image 965
Dave Jarvis Avatar asked Apr 29 '11 06:04

Dave Jarvis


People also ask

Which method adds or replaces a value for a key in a Map?

The set() method adds or updates an entry in a Map object with a specified key and a value.

Can different keys have same value in HashMap?

You should be able to make a copy of a HashMap using its clone method. Note that while this does get you two different maps, the actual values in the two maps are the same. This means that if the copied map's contents are mutable and you change them, they will still change in both places.

Can HashMap store multiple values for same key?

In these cases, we can use Collections such as list, set, etc. to insert multiple values into the same key in HashMap.

What will happen if we put two values with the same key in Map?

As we can see, if we try to insert two values for the same key, the second value will be stored, while the first one will be dropped.


2 Answers

Here is a solution based on @roland's suggestion:

public final class Pair {
  private final Object a;
  private final Object b;

  public Pair(Object a, Object b) {
    this.a = a; 
    this.b = b;
  }

  @Override public boolean equals(Object o) {
    if(o == null || !(o instanceof Pair)) 
      return false;

    Pair that = (Pair) o;
    return this.a.equals(that.a) && this.b.equals(that.b) 
      || this.a.equals(that.b) && this.b.equals(that.a);
  }

  @Override public int hashCode() {
    return a.hashCode() ^ b.hashCode();
  }
}

Then:

Set<Pair> set = new HashSet<Pair>();
for(Bundle primaryOperand : bundleComparators) {
  for(Bundle secondaryOperand : sortedBundles) {
    Pair p = new Pair(primaryOperand.id, secondaryOperand.id);
    if(set.contains(p)) 
      continue;

    set.add(p);
    outputJoin(primaryOperand, secondaryOperand);
  }
}

A subtle point about the solution: you must also override the hashCode() method (hash value must reflect the equality relation), but you must do it in a symmetric way, that is: the hash value of <a,b> must be == to that of <b,a>

like image 144
Itay Maman Avatar answered Sep 28 '22 05:09

Itay Maman


Another idea would be to define a new Class OperatorPair that overrides equals() and use a Set of those, again to be checked with contains(). But your solution should work well, too.

(Also, if you do this, you should override hashCode() as well, for example you could calculate it based on the names of the operands... see e.g. this question for details.)

like image 25
Roland Ewald Avatar answered Sep 28 '22 06:09

Roland Ewald