Каков наиболее эффективный способ хранения этих данных?

Я отвечаю за переписывание старого кода VB. Я понимаю, как это работает, но я чувствую, что есть гораздо более эффективный способ сделать то, что они сделали. Я просто не могу понять, что это такое. Вот надуманный пример, который с точки зрения требований к данным действительно похож на то, что мне нужно делать.

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

Ford Truck F150 red
Ford Truck F150 blue
Ford Truck F150 black
Ford Truck F150 silver
Ford Truck F250 red
Ford Truck F250 green
Ford Sedan Taurus red
Ford Sedan Taurus green
Ford Sedan Taurus white
Ford...
...

Subaru SUV Forester blue
Subaru SUV Forester red
Subaru SUV Outback Black
Subaru SUV Outback Green
Subaru SUV Outback Blue
Subaru SUV Outback Red
Subaru...
...

etc.

Итак, если первый выбор - Subaru, второй ящик (make) должен не иметь возможность выбрать Truck, потому что ни один из Subarus не является грузовиками. Точно так же, если они выбирают Ford, Sedan и Taurus, тогда последний ящик (цвет) должен не показывать вариант выбора синего. Или Черный. Или ничего, кроме красного, зеленого или белого.

Люди, которые написали код передо мной, придумали это (в python-y psuedocode):

def getValidOptions():
    items = []
    for i from 0 to numRows:
        options = getLine().split()
        if selectingManufacturer:
            if options[0] not in items:
                items.append(options[0])
        else if selectingMake:
            if selectedManufacturer == options[0] and options[1] not in items:
               items.append(options[1])
        else if selectingModel:
            if selectedManufacturer == options[0] and selectedMake == options[1] and options[2] not in items:
                items.append(options[2])
        else if selectingColor:
            if selectedManufacturer == options[0] and selectedMake == options[1] and selectedModel == options[2] and options[3] not in items:
                items.append(options[3])
    return items

Я думаю, что это просто отвратительно, как на уровне алгоритма, так и на синтаксическом уровне. Во-первых, он анализирует весь файл, когда ему нужно только прочитать пару строк, если все сделано правильно. Чтобы сделать это еще более неэффективным, мои реальные данные имеют 6 вариантов выбора, а не просто 4. Это также позволяет хранить больше данных, чем нужно, учитывая объем дублирования данных.

Я ищу либо другой способ хранения данных в файле, либо другой способ разбора его, чтобы сделать getValidOptions и более эффективны. Могу ли я сделать это?

9 голосов | спросил DJMcMayhem 16 WedEurope/Moscow2015-12-16T04:22:20+03:00Europe/Moscow12bEurope/MoscowWed, 16 Dec 2015 04:22:20 +0300 2015, 04:22:20

4 ответа


6

Все остальные ответы, которые я прочитал, по-видимому, игнорируют два очень простых правила разработки программного обеспечения:

  • сначала прояснить требования (особенно требования к производительности и хранению)

  • Держите его просто, глупо (см. KISS )

Вы написали «текстовый файл большой», но не пишете too большой, поэтому я предполагаю, что на самом деле ничего не случилось с его размером, кроме чувства вашего кишки. Поэтому, если загрузка файла на самом деле не занимает слишком много времени, а ваш ИТ-отдел или кто-то еще не жалуется на потерянное дисковое пространство, и никто не жалуется на проблемы с сохранением файла, пусть формат файла как есть - не стоит недооценивать значение простоты.

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

Итак, предположим, что программа работает достаточно быстро, сначала спросите, как вы можете улучшить код с точки зрения простоты и принципа DRY? И это действительно точка, которая должна быть улучшена, поскольку текущий код не DRY. В вашем примере появляется четыре раза почти такое же тестирование блока кода, если параметры на «более высоких уровнях» соответствуют текущей строке, что приводит к четырехкратному тому же «приложению» вызова (в вашем реальном коде происходит повторение по крайней мере шесть раз, как вы писали). Вы можете легко избежать этого, введя числовой уровень выбора или передав уже выбранные параметры в упорядоченном списке. Используя ваш псевдокод, это приводит к чему-то по строкам

# selectedOptions is a list, containing either nothing, or "selectedManufacturer"
# or [selectedManufacturer, selectedMake], ..., and so on
def getValidOptions(selectedOptions):
    items = []
    level = selectedOptions.size()
    for i from 0 to numRows:
        options = getLine().split()
        if selectedOptions == options[0:level-1] and options[level] not in item:
            items.append(options[level])
    return items

Таким образом, это по существу тот же алгоритм без повторного кода.

Так как очевидно getValidOptions нужно вызывать более одного раза (по крайней мере один раз за уровень), я предлагаю применить только один оптимизация (если это еще не так): убедитесь, что функция getLine извлекает свои данные из основной памяти и не читает файл с диска снова и снова.

ответил Doc Brown 16 WedEurope/Moscow2015-12-16T10:13:58+03:00Europe/Moscow12bEurope/MoscowWed, 16 Dec 2015 10:13:58 +0300 2015, 10:13:58
6

Ну, данные, которые у вас есть, имеют древовидную структуру, где для каждого производителя у вас есть дерево моделей, а для каждой модели у вас есть цвет (и т. д.).

Итак, вы можете разделить процесс этих данных двумя способами:

  1. После любого обновления текстового файла вы должны обработать этот файл и преобразовать его в древовидную структуру.
  2. При загрузке приложения вы загружаете только древовидную структуру.

Древовидная структура может быть реализована с помощью так называемого хеша , ассоциативного массива или словаря в таких языках, как Java, PHP, Javascript или Python. С этой структурой у вас есть:

  • Первыми ключами являются производители.
  • Их значения - это еще один хэш или словари , где каждый ключ является моделью.
  • Их значения - это цвета. Или другая структура, сохраняющая в своих ключах третий уровень и значение четвертого уровня.
  • И так далее ...

В зависимости от вашего языка программирования это может быть реализовано быстрее или медленнее. Например:

  • C # : вы можете реализовать структуру дерева 1 , а затем пометить ее как сериализуемую.
  • VB.Net : вы можете сгенерировать древовидную структуру в одном приложении и сериализовать ее в файле.
    • Для этого может быть полезно что-то вроде Runtime.Serialization.Formatters.Binary.BinaryFormatter, но я не специалист по сериализации с VB.Net.
  • Javascript : вы можете сгенерировать древовидную структуру в файле JSON, который должен загружаться каждый раз, когда приложение загружается.
  • PHP : вы можете создать сериализованную версию структуры данных дерева или загрузить JSON.
  • Java : вы можете сериализовать эту структуру данных, создав Class, который реализует интерфейс java.io.Serializable литий>

Ссылки

1:

ответил Nicolás 16 WedEurope/Moscow2015-12-16T04:48:33+03:00Europe/Moscow12bEurope/MoscowWed, 16 Dec 2015 04:48:33 +0300 2015, 04:48:33
3

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

  1. Не нужно указывать сериализатор или десериализатор.
  2. Файл доступен для редактирования и может быть запрошен многочисленными существующими программами.
  3. Условная беспорядок, о котором вы упоминаете в вопросе, избегается. Чтобы ограничить выпадающие списки, создайте простую позицию where для каждого столбца (например, select distinct model where manufacturer='ford' and color = 'red').

Это заставляет вас изучать SQL, но избегает необходимости изучать пользовательский формат файла.

ответил Brian 16 WedEurope/Moscow2015-12-16T08:07:37+03:00Europe/Moscow12bEurope/MoscowWed, 16 Dec 2015 08:07:37 +0300 2015, 08:07:37
1

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

Для быстрого доступа храните данные в 6 файлах, где каждый файл является индексом в следующем.

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

Вот как я бы создал индексы для данных примера, которые вы предоставили.

Конечно, файл должен быть отсортирован. Я пронумеровал строки для иллюстрации; номера строк не должны отображаться в файле.

--| file3.dat |--
 0 Ford Truck F150 red
 1 Ford Truck F150 blue
 2 Ford Truck F150 black
 3 Ford Truck F150 silver
 4 Ford Truck F250 red
 5 Ford Truck F250 green
 6 Ford Sedan Taurus red
 7 Ford Sedan Taurus green
 8 Ford Sedan Taurus white
 9 Subaru SUV Forester blue
10 Subaru SUV Forester red
11 Subaru SUV Outback Black
12 Subaru SUV Outback Green
13 Subaru SUV Outback Blue
14 Subaru SUV Outback Red

Чтобы создать первый индекс, сделайте запись для каждой уникальной комбинации первых трех полей в файле. В каждой записи сохраните первый и последний номера строк, в которых отображается эта комбинация.

--| file2.dat |--
 0 Ford Truck F150       0   3
 1 Ford Truck F250       4   5
 2 Ford Sedan Taurus     6   8
 3 Subaru SUV Forester   9  10
 4 Subaru SUV Outback   11  14

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

--| file1.dat |--
 0 Ford Truck        0   1
 1 Ford Sedan        2   2
 2 Subaru SUV        3   4

И третий, верхний уровень в этом случае, индекс.

--| file0.dat |--
 0 Ford          0   1
 1 Subaru        2   2

Я думаю, что я переоцениваю концепцию, но в целом вы создаете индекс, отбрасывая последнее поле и устраняя повторяющиеся записи.

Вы можете дополнительно сократить требования к хранилищу файлов, исключив некоторые избыточные данные.

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

Кроме того, поскольку вы будете использовать только последнее поле в каждой записи для заполнения списка выбора, вам не нужно сохранять другие поля.

Минимальное исполнение индексного каскада заканчивается таким образом, что галочка указывает количество, фактически не сохраненное в файле.

--| file0.dat |--
 0' Ford         0'   1
 1' Subaru       2'   2

--| file1.dat |--
 0' Truck        0'   1
 1' Sedan        2'   2
 2' SUV          3'   4

--| file2.dat |--
 0' F150         0'   3
 1' F250         4'   5
 2' Taurus       6'   8
 3' Forester     9'  10
 4' Outback     11'  14

--| file3.dat |--
 0' red
 1' blue
 2' black
 3' silver
 4' red
 5' green
 6' red
 7' green
 8' white
 9' blue
10' red
11' Black
12' Green
13' Blue
14' Red

Когда вы заполняете список выбора из индекса, вы используете «первый» и «последний» индексы из выбора пользователя в предыдущем индексе для ограничения прочитанных строк.

Пример:

Вы заполняете первый список выбора из всех file0.dat. (Форд, Субару)

Пользователь выбирает «Форд». Соответствующие индексы равны 0 и 1.

Вы заполняете второй список выбора из строк от 0 до 1 из file1.dat. (Грузовик, седан)

Пользователь выбирает «Седан». Соответствующие индексы равны 2 и 2.

Как вы можете видеть, к тому времени, когда пользователь выбрал, например, «Ford» «Sedan» «Taurus», вы обнаружите, что вам нужны только строки с 6 по 8 из file3.dat, чтобы заполнить четвертый список выбора.

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

ДОБАВЛЕНО: при дальнейшей мысли файлы могут быть объединены в один.

--| file.dat |--
 0' -            1'   2
 1' Ford         3'   4
 2' Subaru       5'   5
 3' Truck        6'   7
 4' Sedan        8'   8
 5' SUV          9'  10
 6' F150        11'  14
 7' F250        15'  16
 8' Taurus      17'  19
 9' Forester    20'  21
10' Outback     22'  25
11' red          -'   -
12' blue         -'   -
13' black        -'   -
14' silver       -'   -
15' red          -'   -
16' green        -'   -
17' red          -'   -
18' green        -'   -
19' white        -'   -
20' blue         -'   -
21' red          -'   -
22' Black        -'   -
23' Green        -'   -
24' Blue         -'   -
25' Red          -'   -

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

ответил A. I. Breveleri 16 WedEurope/Moscow2015-12-16T07:48:41+03:00Europe/Moscow12bEurope/MoscowWed, 16 Dec 2015 07:48:41 +0300 2015, 07:48:41

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132