<p>I have two collections of the same object, <code>Collection&lt;Foo&gt; oldSet</code> and <code>Collection&lt;Foo&gt; newSet</code>.  The required logic is as follow:</p>

<ul>
<li>if <code>foo</code> is in(*) <code>oldSet</code> but not <code>newSet</code>, call <code>doRemove(foo)</code></li>
<li>else if <code>foo</code> is not in <code>oldSet</code> but in <code>newSet</code>, call <code>doAdd(foo)</code></li>
<li>else if <code>foo</code> is in both collections but modified, call <code>doUpdate(oldFoo, newFoo)</code></li>
<li>else if <code>!foo.activated &amp;&amp; foo.startDate &gt;= now</code>, call <code>doStart(foo)</code></li>
<li>else if <code>foo.activated &amp;&amp; foo.endDate &lt;= now</code>, call <code>doEnd(foo)</code></li>
</ul>

<p>(*) "in" means the unique identifier matches, not necessarily the content.</p>

<p>The current (legacy) code does many comparisons to figure out <code>removeSet</code>, <code>addSet</code>, <code>updateSet</code>, <code>startSet</code> and <code>endSet</code>, and then loop to act on each item.</p>

<p>The code is quite messy (partly because I have left out some spaghetti logic already) and I am trying to refactor it.  Some more background info:</p>

<ul>
<li>As far as I know, the <code>oldSet</code> and <code>newSet</code> are actually backed by <code>ArrayList</code></li>
<li>Each set contains less than 100 items, most likely max out at 20</li>
<li>This code is called frequently (measured in millions/day), although the sets seldom differ</li>
</ul>

<p>My questions:</p>

<ul>
<li>If I convert <code>oldSet</code> and <code>newSet</code> into <code>HashMap&lt;Foo&gt;</code> (order is not of concern here), with the IDs as keys, would it made the code easier to read and easier to compare?  How much of time &amp; memory performance is loss on the conversion?</li>
<li>Would iterating the two sets and perform the appropriate operation be more efficient and concise?</li>
</ul>

[{'answer_id': 23469, 'author': 'Mike Deck', 'author_id': 1247, 'author_profile': 'https://Stackoverflow.com/users/1247', 'pm_score': -1, 'selected': False, 'text': "<p>For a set that small is generally not worth it to convert from an Array to a HashMap/set.  In fact, you're probably best off keeping them in an array and then sorting them by key and iterating over both lists simultaneously to do the comparison.</p>\n"}, {'answer_id': 23944, 'author': 'martinatime', 'author_id': 1353, 'author_profile': 'https://Stackoverflow.com/users/1353', 'pm_score': 4, 'selected': False, 'text': "<p>I have created an approximation of what I think you are looking for just using the Collections Framework in Java. Frankly, I think it is probably overkill as @Mike Deck points out. For such a small set of items to compare and process I think arrays would be a better choice from a procedural standpoint but here is my pseudo-coded (because I'm lazy) solution. I have an assumption that the Foo class is comparable based on it's unique id and not all of the data in it's contents:</p>\n\n<pre><code>Collection&lt;Foo&gt; oldSet = ...;\nCollection&lt;Foo&gt; newSet = ...;\n\nprivate Collection difference(Collection a, Collection b) {\n    Collection result = a.clone();\n    result.removeAll(b)\n    return result;\n}\n\nprivate Collection intersection(Collection a, Collection b) {\n    Collection result = a.clone();\n    result.retainAll(b)\n    return result;\n}\n\npublic doWork() {\n    // if foo is in(*) oldSet but not newSet, call doRemove(foo)\n    Collection removed = difference(oldSet, newSet);\n    if (!removed.isEmpty()) {\n        loop removed {\n            Foo foo = removedIter.next();\n            doRemove(foo);\n        }\n    }\n    //else if foo is not in oldSet but in newSet, call doAdd(foo)\n    Collection added = difference(newSet, oldSet);\n    if (!added.isEmpty()) {\n        loop added  {\n            Foo foo = addedIter.next();\n            doAdd(foo);\n        }\n    }\n\n    // else if foo is in both collections but modified, call doUpdate(oldFoo, newFoo)\n    Collection matched = intersection(oldSet, newSet);\n    Comparator comp = new Comparator() {\n        int compare(Object o1, Object o2) {\n            Foo f1, f2;\n            if (o1 instanceof Foo) f1 = (Foo)o1;\n            if (o2 instanceof Foo) f2 = (Foo)o2;\n            return f1.activated == f2.activated ? f1.startdate.compareTo(f2.startdate) == 0 ? ... : f1.startdate.compareTo(f2.startdate) : f1.activated ? 1 : 0;\n        }\n\n        boolean equals(Object o) {\n             // equal to this Comparator..not used\n        }\n    }\n    loop matched {\n        Foo foo = matchedIter.next();\n        Foo oldFoo = oldSet.get(foo);\n        Foo newFoo = newSet.get(foo);\n        if (comp.compareTo(oldFoo, newFoo ) != 0) {\n            doUpdate(oldFoo, newFoo);\n        } else {\n            //else if !foo.activated &amp;&amp; foo.startDate &gt;= now, call doStart(foo)\n            if (!foo.activated &amp;&amp; foo.startDate &gt;= now) doStart(foo);\n\n            // else if foo.activated &amp;&amp; foo.endDate &lt;= now, call doEnd(foo)\n            if (foo.activated &amp;&amp; foo.endDate &lt;= now) doEnd(foo);\n        }\n    }\n}\n</code></pre>\n\n<p>As far as your questions:\nIf I convert oldSet and newSet into HashMap (order is not of concern here), with the IDs as keys, would it made the code easier to read and easier to compare? How much of time &amp; memory performance is loss on the conversion?\nI think that you would probably make the code more readable by using a Map BUT...you would probably use more memory and time during the conversion.</p>\n\n<p>Would iterating the two sets and perform the appropriate operation be more efficient and concise?\nYes, this would be the best of both worlds especially if you followed @Mike Sharek 's advice of Rolling your own List with the specialized methods or following something like the Visitor Design pattern to run through your collection and process each item.</p>\n"}, {'answer_id': 36997, 'author': 'Bartosz Bierkowski', 'author_id': 3666, 'author_profile': 'https://Stackoverflow.com/users/3666', 'pm_score': 2, 'selected': False, 'text': '<p>I\'d move to lists and solve it this way:<br/></p>\n\n<ol>\n<li>Sort both lists by id ascending using custom <a href="http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/util/Comparator.html" rel="nofollow noreferrer">Comparator</a> if objects in lists aren\'t <a href="http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/lang/Comparable.html" rel="nofollow noreferrer">Comparable</a></li>\n<li>Iterate over elements in both lists like in merge phase in <a href="http://en.wikipedia.org/wiki/Merge_sort" rel="nofollow noreferrer">merge sort algorithm</a>, but instead of merging lists, you check your logic.</li>\n</ol>\n\n<p>The code would be more or less like this:</p>\n\n<pre><code>/* Main method */\nprivate void execute(Collection&lt;Foo&gt; oldSet, Collection&lt;Foo&gt; newSet) {\n  List&lt;Foo&gt; oldList = asSortedList(oldSet);\n  List&lt;Foo&gt; newList = asSortedList(newSet);\n\n  int oldIndex = 0;\n  int newIndex = 0;\n  // Iterate over both collections but not always in the same pace\n  while( oldIndex &lt; oldList.size() \n      &amp;&amp; newIndex &lt; newIndex.size())  {\n    Foo oldObject = oldList.get(oldIndex);\n    Foo newObject = newList.get(newIndex);\n\n    // Your logic here\n    if(oldObject.getId() &lt; newObject.getId()) {\n      doRemove(oldObject);\n      oldIndex++;\n    } else if( oldObject.getId() &gt; newObject.getId() ) {\n      doAdd(newObject);\n      newIndex++;\n    } else if( oldObject.getId() == newObject.getId() \n            &amp;&amp; isModified(oldObject, newObject) ) {\n      doUpdate(oldObject, newObject);\n      oldIndex++;\n      newIndex++;\n    } else {\n      ... \n    }\n  }// while\n\n  // Check if there are any objects left in *oldList* or *newList*\n\n  for(; oldIndex &lt; oldList.size(); oldIndex++ ) {\n    doRemove( oldList.get(oldIndex) );  \n  }// for( oldIndex )\n\n  for(; newIndex &lt; newList.size(); newIndex++ ) {\n    doAdd( newList.get(newIndex) );\n  }// for( newIndex ) \n}// execute( oldSet, newSet )\n\n/** Create sorted list from collection \n    If you actually perform any actions on input collections than you should \n    always return new instance of list to keep algorithm simple.\n*/\nprivate List&lt;Foo&gt; asSortedList(Collection&lt;Foo&gt; data) {\n  List&lt;Foo&gt; resultList;\n  if(data instanceof List) {\n     resultList = (List&lt;Foo&gt;)data;\n  } else {\n     resultList = new ArrayList&lt;Foo&gt;(data);\n  }\n  Collections.sort(resultList)\n  return resultList;\n}\n</code></pre>\n'}, {'answer_id': 1167234, 'author': 'user143081', 'author_id': 143081, 'author_profile': 'https://Stackoverflow.com/users/143081', 'pm_score': 5, 'selected': False, 'text': '<p>Apache\'s commons.collections library has a CollectionUtils class that provides easy-to-use methods for Collection manipulation/checking, such as intersection, difference, and union.</p>\n\n<p>The org.apache.commons.collections.CollectionUtils API docs are <a href="http://commons.apache.org/proper/commons-collections/javadocs/api-4.0/index.html" rel="noreferrer">here</a>.</p>\n'}, {'answer_id': 3104434, 'author': 'Sharan Rajendran', 'author_id': 374532, 'author_profile': 'https://Stackoverflow.com/users/374532', 'pm_score': 2, 'selected': False, 'text': '<p>I think the easiest way to do that is by using apache collections api - CollectionUtils.subtract(list1,list2) as long the lists are of the same type. </p>\n'}, {'answer_id': 4469413, 'author': 'Lijo Mathew', 'author_id': 545907, 'author_profile': 'https://Stackoverflow.com/users/545907', 'pm_score': -1, 'selected': False, 'text': '<p>For comaparing a list or set we can use <code>Arrays.equals(object[], object[])</code>. It will check for the values only. To get the <code>Object[]</code> we can use <code>Collection.toArray()</code> method.</p>\n'}, {'answer_id': 8638140, 'author': 'Vitalii Fedorenko', 'author_id': 288671, 'author_profile': 'https://Stackoverflow.com/users/288671', 'pm_score': 5, 'selected': False, 'text': '<p>You can use Java 8 streams, for example</p>\n\n<pre><code>set1.stream().filter(s -&gt; set2.contains(s)).collect(Collectors.toSet());\n</code></pre>\n\n<p>or  <a href="http://guava-libraries.googlecode.com/svn/tags/release04/javadoc/com/google/common/collect/Sets.html" rel="noreferrer">Sets</a> class from <a href="http://code.google.com/p/guava-libraries/" rel="noreferrer">Guava</a>:</p>\n\n<pre><code>Set&lt;String&gt; intersection = Sets.intersection(set1, set2);\nSet&lt;String&gt; difference = Sets.difference(set1, set2);\nSet&lt;String&gt; symmetricDifference = Sets.symmetricDifference(set1, set2);\nSet&lt;String&gt; union = Sets.union(set1, set2);\n</code></pre>\n'}, {'answer_id': 35296176, 'author': 'pooja', 'author_id': 1854406, 'author_profile': 'https://Stackoverflow.com/users/1854406', 'pm_score': 0, 'selected': False, 'text': '<pre><code>public static boolean doCollectionsContainSameElements(\n        Collection&lt;Integer&gt; c1, Collection&lt;Integer&gt; c2){\n\n    if (c1 == null || c2 == null) {\n        return false;\n    }\n    else if (c1.size() != c2.size()) {\n        return false;\n    } else {    \n        return c1.containsAll(c2) &amp;&amp; c2.containsAll(c1);\n    }       \n}\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/23445', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/2551/']