Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mutate an array of integers in-place in swift through filtering

One can filter an array like this in swift:

var numbers = Array(1...1000000)
numbers = numbers.filter( { return $0 % 2 == 0  } ) 

Is it possible to filter and avoid the copy operation, that occurs when the filtering is done, e.g mutating the original array.

In a similar way to this pseudocode: numbers.MutablefilterOperation({ return $0 % 2 == 0})

In C++ the equvivalent to what is going on in Swift above would be:

std::vector<int> originalNumbers(1000000);
std::vector<int> newNumbers;
std::copy_if (originalNumbers.begin(), originalNumbers.end(), std::back_inserter(newNumbers), [](int i) { return i % 2 == 0 } );

What I would like to achieve for performance reasons:

std::vector<int> originalNumbers(1000000);
auto pos = std::remove_if(originalNumbers.begin(), originalNumbers.end(), [](int x) { return x % 2 == 0; });
originalNumbers.erase(pos, originalNumbers.end());
like image 374
JKRT Avatar asked Oct 19 '22 07:10

JKRT


1 Answers

This implementation should do the filtering without having to make a temporary copy of the entire array in the process (unless a copy of it is referenced by another variable, see "Copy on Write")

extension Array {
    mutating func filterInPlace(isIncluded: (Element) throws -> Bool) rethrows {
        var writeIndex = self.startIndex
        for readIndex in self.indices {
            let element = self[readIndex]
            let include = try isIncluded(element)
            if include {
                if writeIndex != readIndex {
                    self[writeIndex] = element
                }
                writeIndex = self.index(after: writeIndex)
            }
        }
        self.removeLast(self.distance(from: writeIndex, to: self.endIndex))
    }
}

// example:
var arr = [6,2,6,5,2,5,6,2,2,1,6,7,3]
arr.filterInPlace { $0 % 2 == 1 }
print(arr) // [5, 5, 1, 7, 3]
like image 179
Vadim Yelagin Avatar answered Oct 21 '22 05:10

Vadim Yelagin