Эффективность использования filter{where:} по сравнению с removeAll{where:} при изменении значения параметра

В 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 еще более эффективным в этом сценарии? Или лучше придерживаться функции фильтра?» почему бы вам не измерить приборами и не узнать?

matt 09.04.2019 20:32
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
1
771
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Остерегайтесь преждевременной оптимизации. Эффективность метода часто зависит от ваших конкретных данных и конфигурации, и, если вы не работаете с большим набором данных или не выполняете много операций одновременно, вряд ли он окажет существенное влияние в любом случае. Если это не так, вы должны отдать предпочтение более читабельному и поддерживаемому решению.

Как правило, просто используйте 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:)

Отличный комментарий, разделение используется недостаточно.

Justin Meiners 15.02.2022 00:30

Другие вопросы по теме