Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Algorithm for comparing two lists

I have a list of objects that I am displaying on the screen. The user can change them as they like, and then hit submit. In the submit method I am taking the original list, which I stored, and the current list, and comparing them. I have to create a third list that contains all the objects that were added, removed, or changed with an action code to specify which it was. The objects have an id to identify them, which defaults to 0.

How can I do this? This is the best I could come up with (pseudocode) but it seems sloppy.

for (currentObject : objects in current list)
    if (currentObject.id is 0)
        //Was added
    for (oldObject : objects in original list)
        if (currentObject.id == oldObject.id)
            //Existed - compare other fields to see if changed

for (oldObject1 : objects in original list)
    boolean existed = false;
    for (currentObject1 : objects in current list)
        if(oldObject1.id == currentObject1.id)
            existed=true;
    if (!existed)
        //Was removed
like image 725
bhouse Avatar asked Jun 19 '13 19:06

bhouse


People also ask

How do you compare values in two lists?

counter() method can be used to compare lists efficiently. The counter() function counts the frequency of the items in a list and stores the data as a dictionary in the format <value>:<frequency>. If two lists have the exact same dictionary output, we can infer that the lists are the same.

How do you compare two algorithms?

To compare algorithms with very different bounds, we can just ignore the constants. We write T[PTA] = O(sqrt(N)) or T[B] = O(sqrt(N) log_2(N)). This is called big-O notation.

Can you compare lists with == in Python?

Using list. sort() method sorts the two lists and the == operator compares the two lists item by item which means they have equal data items at equal positions. This checks if the list contains equal data item values but it does not take into account the order of elements in the list.


2 Answers

If ordering doesn't matter and all you care about is whether the elements were added or removed, you might want to consider changing your data structures and using Set rather than List. The Set type is specifically designed to determine whether or not elements exist and to do so efficiently, at the cost that you no longer remember the order of the elements.

For example, using HashSet, you could do the following:

Set<T> oldElems = new HashSet<T>(originalList);
Set<T> newElems = new HashSet<T>(currentList);

for (T obj : oldElems) {
    if (!newElems.contains(obj)) {
        /* ... this object was removed ... */
    }
}

for (T obj : newElems) {
    if (!oldElems.contains(obj)) {
        /* ... this object was added ... */
    }
}

Hope this helps!

like image 80
templatetypedef Avatar answered Sep 26 '22 02:09

templatetypedef


You can do it with one loop, by continuously maintaining the 3-way result list. If you can override equals() to depend on ids, that's fine. If not, check the code under update.

Here's the code, see the explanation below:

List<T> origList = ...;
List<T> newList = ...;

List<T> addedList = new ArrayList<T>();
List<T> deletedList = new ArrayList<T>();
List<T> changedList = new ArrayList<T>();

deletedList.addAll(origList);

for(T t : newList) {
    int origIndex = deletedList.indexOf(t);
    if (origIndex < 0) {
        addedList.add(t);
    } else {
        T origT = deletedList.remove(origIndex);
        if(t.compareTo(origT) != 0) {
            changedList.add(t);
        }
    }
}

Note that I presumed that equals() will check the id, and compareTo() will check all other fields.

Explanation:

You remove all elements from deletedList that were also present in newList, so the result is the deleted items.

You add all new elements to the addedList that were not present in the original list.

If both are present and the objects differ, they'll go to the changedList.

If both are present and the objects are the same then we don't add it anywhere.

Notes:

If new objects have an ID of 0, they will not be present in origList (since we suppose they have been already created).

When I last time implemented this, I created a separate method to compare the objects field-by-field, so I could separate the comparison logic from standard Java methods (actually it was also declared on an interface)

I created this with Lists, but actually you can use it with any type of Collection. Using with List will preserve the original order.

Update:

Try overriding your equals this way (I skipped the typecheck and the casting):

public boolean equals(T other) {
    if (this.id == 0) {
        return this == other;
    }
    return this.id == other.id;
}

The not-yet-created instances are equal to themselves only. The already-created ones are checked by id.

like image 30
gaborsch Avatar answered Sep 26 '22 02:09

gaborsch