Самый быстрый способ найти firstIndex в большом массиве (1000) Swift

Есть ли более быстрый способ найти индекс в массиве пользовательских объектов?

У меня есть массив, который имеет количество около 1000. И в каждом SectionIndex есть MainIndex со всеми моими свойствами, каждый SectionIndex имеет примерно 15 частей MainIndex. SectionIndex используется для заголовков разделов TableView, а часть .data[MainIndex] заполняет строки в каждом разделе.

После запуска инструментов (профилирование времени) из 5 секунд, необходимых для запуска моего приложения, строка (array.firstIndex) заняла 3,89 секунды, могу ли я как-то ускорить ту часть, где я нахожу индекс?

var array: [SectionIndex] = [SectionIndex]()

Основная часть в функции:

let title = "\(dateMonth), \(dateYear)"
if let offset = array.firstIndex(where: { $0.title == title })
{
     array[offset].data.append(insert)
     if let mins = array[offset].minutes {
     array[offset].minutes = mins + timeToMinutes(minutes)
     }
}
else
{
     let insert2 = SectionIndex(index: array.count, title: title, date: date, data: [insert], minutes: timeToMinutes(minutes))
     array.append(insert2)
}

Индекс раздела

class SectionIndex {
let index: Int?
let title: String?
let date: Date?
var data: [MainIndex] = [MainIndex]()
var minutes: Int?
init(index: Int, title: String, date: Date, data: [MainIndex], minutes: Int)
{
    self.index = index
    self.title = title
    self.date = date
    self.data = data
    self.minutes = minutes
}
}

Причина, по которой мне нужно найти или добавить индекс:

Мои данные относятся к разным месяцам года примерно за 1000 месяцев, всякий раз, когда месяц и год найдены первыми, они становятся заголовком, в следующий раз, когда он уже существует, я добавляю данные в этот раздел.

Xcode 12.2 (Свифт 5)

Если что-то занимает много времени, не делайте этого в основном потоке во время запуска. Запуск должен быть быстрым.

matt 12.12.2020 23:32

Как часто это array.firstIndex называется? 3,9 секунды кажутся слишком большим временем, если только вы не вызываете его очень часто. Кроме того, вы уверены, что свойства в SectionIndex должны быть необязательными? Судя по тому, что вы показываете init, вы можете избавиться от всех этих ? меток.

Gereon 12.12.2020 23:32

Да, несколько секунд для всего 1000 элементов немыслимы. Происходит что-то еще. (Кстати, я предполагаю, что вы профилируете выпуск/оптимизированные сборки, верно?)

Rob 12.12.2020 23:42

Есть ли какие-то вложенные циклы или что-то в этом роде в вашем реальном коде. Не может быть, чтобы один поиск занял так много времени, но мне интересно, делаете ли вы это постоянно. Отвечая на ваш вопрос, способы его ускорения заключаются в том, чтобы улучшить поиск до O (1) (например, с использованием словаря, ваших собственных хеш-таблиц и т. д.). Но не похоже, чтобы у нас было достаточно, чтобы диагностировать, что происходит...

Rob 12.12.2020 23:46

Да, в основном, так как мне нужно добавить 1000 разделов и 15 записей в каждом разделе. Всего в базе данных 15 000 записей, поэтому эта строка выполняется 15 000 раз, чтобы проверить, существует ли заголовок или его нужно добавить.

Paul 13.12.2020 06:23

Причина, по которой он находится в основном потоке при запуске, заключается в том, что это основные данные, которые должен видеть пользователь. Только это медленно, когда пользователь достигает 15 000, что является максимальным. Гораздо быстрее, когда их меньше. Но я тестирую наихудший сценарий, чтобы иметь минимальное время загрузки. Что касается опционов, это правда, что на самом деле сэкономит еще долю секунды на разворачивании большого количества опционов.

Paul 13.12.2020 06:26

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

Rob 14.12.2020 05:43

Да, я понимаю, что вы имеете в виду, я изначально думал об анимации загрузки, но проблема в том, что когда количество введенных данных ниже 6000 или iPhone XS Max, анимация будет появляться и исчезать, поскольку это происходит быстро. Возникает только проблема, которая будет редкостью, когда пользователь начнет достигать максимальных данных. Я думаю, у меня могут быть оба варианта в зависимости от времени загрузки? Как только время функции превысит пороговое значение, я могу сохранить переменную медленной загрузки, которая будет запускать анимацию загрузки при каждом запуске. Кстати, спасибо за вашу помощь, время, которое я сэкономил на загрузке, потрясающе, просто с использованием словаря.

Paul 14.12.2020 13:29
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
1
8
476
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В соответствии с предложениями комментариев и предложением словаря Роба я адаптировал следующее, что решило мою проблему и значительно улучшило производительность!

 var currentIndex: Int = 0
 var dic: [String: Int] = [:]

 // Code below runs 15,000 times for each database entry
 if let offset = dic[title]
 {
     array[offset].data.append(insert)
     if let mins = array[offset].minutes { array[offset].minutes = mins + timeToMinutes(minutes) }
 }
 else
 {
       let insert2 = SectionIndex(index: currentIndex, title: title, date: date, data: [insert], minutes: timeToMinutes(minutes))
       dic[title] = currentIndex
       currentIndex += 1
       array.append(insert2)
 }

Я также избавился от опций в моей основной части с большим количеством записей, что еще больше улучшило производительность загрузки. Результаты с вышеизложенным:

Основная тема: 1,91 с

Старт: 1,77 с

Инициализация системного интерфейса: 1,29 с

Инициализация UIKit: 933 мс

Запуск начального рендеринга кадра: 1,64 с

Я доволен результатом, так как это наихудший случай загрузки 15 000 записей в 1000 разделов, но если у кого-то есть какие-либо дополнительные предложения и улучшения, дайте мне знать.

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