0

I have list which is sorted by user. then I get the list from server again.
some elements might be deleted or added. I want to sort the new array based on the sorting of the previous array then add new elements.

Example
oldElementList: [1, 4, 2, 8] ---> user set this order
newElementList: [1, 4, 3, 8]

What I want as output is: [1, 4, 8, 3]

Actually element are not numbers they are objects. and when they are gotten from server some of their property values might have changed.

My answer:

for (ElementModel *oldElement in oldElementList) {
            for (ElementModel * newElement in newElementList) {
                if ([newElement.number isEqualToString: oldElement.number]) {
                    [sortedArray addObject: newElement];
                    [newElementList removeObject: newElement];

                    break;
                }
            }
        }

        for (ElementModel *newElement in newElementList) {
            [sortedArray addObject: newElement];
        }

I don't think my answer is ok, I want to make it better in performance or in any other aspect that I have not considered.

2
  • 2
    The new output should be [1, 4, 8, 3] because 2 was removed, and 3 is added to the end because it's a new element? Commented Apr 22, 2019 at 13:52
  • @NTitH yes. Exactly Commented Apr 22, 2019 at 19:15

1 Answer 1

1

Which sorting algorithm is appropriate depends very much on your data, e.g.:
- Is the data set to be sorted large (only then, a sophisticated algorithms may pay off)?
- Is the data set to be sorted completely random or presorted?
From your description it seems to me that you have a large data set (otherwise any algorithms giving the correct result would be probably fine, including your own that has a O(n^2) complexity), and that it is presorted, i.e. there are only only a few additions and deletions (otherwise it may not be so important to keep the original sorting).
If so, what about the following algorithm (sorry, it is in Swift, but could surely easily be converted to Obj-C):

let old = [1, 4, 2, 7, 8]
let new = [1, 4, 3, 8, 2]

var oldIndexed: [Int: Int] = [:]
for i in 0 ..< old.count {
    oldIndexed[old[i]] = i
}
var newIndexed: [Int: Int] = [:]
for i in 0 ..< new.count {
    newIndexed[new[i]] = oldIndexed[new[i]] ?? old.count
}
var resultArray: [(Int, Int)] = []
for (key, value) in newIndexed {
    resultArray.append((key, value))
}
resultArray = resultArray.sorted { (first, second) -> Bool in
    first.1 < second.1
}
let result = resultArray.map{ $0.0 } // Here: [1, 4, 2, 8, 3]

The idea is to give the old data elements an index, and every new data element the same index. This is done by using dictionaries, since there every element can be accessed by its key in O(1). New elements get a larger index (this could also be a counter to make it clearer). Then the new dictionary is converted back to an array, that is then sorted by its index. Eventually, the index is dropped, and the result is ready.
I guess, the complexity of this algorithm is determined by the sort function that should be optimal since it is implemented in the standard library.

EDIT:

I did not program in Obj-C for a long time, but tried it just for fun once more:

NSArray *old = @[@1, @4, @2, @7, @8];
NSArray *new = @[@1, @4, @3, @8, @2];

NSMutableDictionary *oldIndexed = [[NSMutableDictionary alloc] init];
for (int i = 0; i < old.count; i++) {
    [oldIndexed setValue:[NSNumber numberWithInt: i] forKey: old[i]];
}

NSMutableDictionary *newIndexed = [[NSMutableDictionary alloc] init];
long counter = old.count;
for (int i = 0; i < old.count; i++) {
    NSNumber *oldIndexOfNewValue = oldIndexed[new[i]];
    NSNumber *newIndex;
    if (oldIndexOfNewValue != nil) {
        newIndex = oldIndexOfNewValue;
    } else {
        newIndex = [NSNumber numberWithLong: counter];
        counter++;
    }
    [newIndexed setValue: newIndex forKey: new[i]];
}

NSMutableArray *resultArray = [[NSMutableArray alloc] init];
NSArray *allKeysInNewIndexed = newIndexed.allKeys;
for (int i = 0; i < allKeysInNewIndexed.count; i++) {
    NSNumber *nextKey = allKeysInNewIndexed[i];
    NSArray *nextPair = @[nextKey, newIndexed[nextKey]];
    [resultArray addObject: nextPair];
}

NSArray *sortedResultArray;
sortedResultArray = [resultArray sortedArrayUsingComparator: ^NSComparisonResult(NSArray *first, NSArray *second) {
    NSNumber *firstIndex = first[1];
    NSNumber *secondIndex = second[1];
    return [firstIndex compare: secondIndex];
}];

NSMutableArray * result = [[NSMutableArray alloc] init];
for (int i = 0; i < sortedResultArray.count; i++) {
    [result addObject: sortedResultArray[i][0]];
}
Sign up to request clarification or add additional context in comments.

2 Comments

This is a good way to do it in Swift, and something similar is possible in Obj-C though you'd probably not use an array of tuples. The sorting methods provide by Swift are not guaranteed to be stable, that is elements which compare equal may not be in the same order after the sort. As you use the same sorting key value, old.count, for every added item they may not retain their same relative order after the sort. I think you'll find you can address this by using old.count + i for the key values of the added items.
@CRD: You are right, and I wanted to indicate this by my remark this could also be a counter to make it clearer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.