В Swift 4.2 появился новый функция removeAll {где:}. Из того, что я прочитал, предполагается, что это более эффективно, чем использование фильтра {где:}. У меня есть несколько сценариев в моем коде:
private func getListOfNullDates(list: [MyObject]) -> [MyObject] {
return list.filter{ $0.date == nil }
.sorted { $0.account?.name < $1.account?.name }
}
Однако я не могу использовать removeAll{where:} с параметром, потому что это константа. Поэтому мне нужно было бы переопределить его следующим образом:
private func getListOfNullDates(list: [MyObject]) -> [MyObject] {
var list = list
list.removeAll { $0.date == nil }
return list.sorted { $0.account?.name < $1.account?.name }
}
Является ли использование функции removeAll еще более эффективным в этом сценарии? Или лучше придерживаться функции фильтра?
Остерегайтесь преждевременной оптимизации. Эффективность метода часто зависит от ваших конкретных данных и конфигурации, и, если вы не работаете с большим набором данных или не выполняете много операций одновременно, вряд ли он окажет существенное влияние в любом случае. Если это не так, вы должны отдать предпочтение более читабельному и поддерживаемому решению.
Как правило, просто используйте removeAll
, когда вы хотите изменить исходный массив, и filter
, когда этого не требуется. Если вы определили его как потенциальное узкое место в вашей программе, тогда протестируйте его, чтобы увидеть, есть ли разница в производительности.
Спасибо за этот вопрос ??
У меня есть эталонный обе функции, использующие этот код в TIO:
let array = Array(0..<10_000_000)
do {
let start = Date()
let filtering = array.filter { $0 % 2 == 0 }
let end = Date()
print(filtering.count, filtering.last!, end.timeIntervalSince(start))
}
do {
let start = Date()
var removing = array
removing.removeAll { $0 % 2 == 0 }
let end = Date()
print(removing.count, removing.last!, end.timeIntervalSince(start))
}
(Чтобы removing
и filtering
были идентичными, замыкание, переданное removeAll
, должно было быть { $0 % 2 != 0 }
, но я не хотел давать преимущество ни одному из фрагментов, используя более быстрый или медленный оператор сравнения.)
И действительно, removeAll(where:)
работает быстрее, когда вероятность удаления элементов (назовем это Pr
) равна 50%! Вот результаты тестов:
filter : 94ms
removeAll : 74ms
Это тот же случай, когда Pr
менее 50%.
В противном случае фильтрация быстрее для более высокого Pr
.
Следует иметь в виду, что в вашем коде list
является изменчивым, и это открывает возможность для случайных модификаций.
Лично я предпочел бы производительность старым привычкам, и в некотором смысле этот вариант использования более удобочитаем, поскольку намерение более ясно.
Под удалением на месте подразумевается замена элементов в массиве таким образом, чтобы удаляемые элементы располагались после определенного опорного индекса. Элементы, которые нужно сохранить, - это те, которые находятся перед элементом поворота:
var inPlace = array
let p = inPlace.partition { $0 % 2 == 0 }
Имейте в виду, что partition(by:)
не сохраняет исходный порядок.
Этот подход часы лучше, чем removeAll(where:)
Отличный комментарий, разделение используется недостаточно.
«Является ли использование функции removeAll еще более эффективным в этом сценарии? Или лучше придерживаться функции фильтра?» почему бы вам не измерить приборами и не узнать?