Який найефективніший спосіб зберігання цих даних?


9

Я відповідаю за перезапис старого коду 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, у другому ящику (марці) не повинно бути можливості вибору Вантажівки, оскільки жоден із 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функцію більш красивою та ефективнішою. Чи є якісь способи я це зробити?


2
чому б не використовувати базу даних?
Tulains Córdova

Відповіді:


6

Усі інші відповіді, які я читаю, здаються, ігнорують два дуже основних правила розробки програмного забезпечення:

  • спочатку уточнити вимоги (особливо вимоги до продуктивності та зберігання)

  • Нехай це буде просто, тупо (див. KISS )

Ви написали "текстовий файл великий", але ви не написали занадто великого розміру, тому я припускаю, що насправді немає нічого поганого в його розмірі, крім вашого відчуття кишки. Тож якщо завантаження файлу насправді не займе багато часу, а ваш ІТ-відділ чи хтось інший не скаржиться на витрачений дисковий простір, і ніхто не скаржиться на проблеми з підтриманням файлу, нехай це не буде недооцінювати значення простоти

Ви також скаржитеся на ефективність алгоритму, який насправді не настільки ефективний, як міг би бути, але він має одну дуже велику перевагу: він просто мертвий і працює. Тому, поки це досить ефективно, не застосовуйте жодної передчасної оптимізації.

Отже, припустимо, що програма працює досить швидко. Перш за все, слід запитати, як можна вдосконалити код з точки зору простоти та принципу 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функція витягує свої дані з основної пам'яті, а не читати файл з диска знову і знову.


Ви хочете перемістити "level = selectedOptions.size ()" перед циклом numRows.
А. І. Бревелері

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: https://dvanderboom.wordpress.com/2008/03/15/treet-implementing-a-non-binary-tree-in-c/
- Повне пояснення щодо реалізації дерева в C #.
- Шукайте коментар, де хтось запитує про серіалізацію цього об’єкта, і відповідь на цей коментар.


1
Так, я думав про використання дерева, але не знаю, чи це найкраща ідея, оскільки в C # немає вбудованої структури дерева (про яку я знаю), і проект досить малий, тому я не знаю, чи варто було б витратити дуже багато часу на роботу над tree with an arbitrary number of nodesвпровадженням.
Джеймс

На сьогоднішній день я не знаю C #, але принаймні в інших мовах, таких як Java та PHP, ви можете мати якісь словники, де кожен ключ може мати значення іншого словника.
Ніколас

Я оновив свою відповідь. Подивіться, що ви думаєте про альтернативу хешу чи словника. Я також додав посилання на цікаву статтю.
Ніколас

3

Один з простих способів зберігання даних - це просто вставити їх у базу даних SQLite. SQLite, на відміну від більшості баз даних SQL, добре підходить для використання у форматі файлу додатків. Цей підхід має ряд переваг:

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

Це змушує вас вивчати SQL, але уникає необхідності засвоювати спеціальний формат файлу.


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. (Ford, Subaru)

Користувач вибирає "Форд". Відповідні підписки - 0 і 1.

Ви заповнюєте другий список вибору з рядків 0 по 1 file1.dat. (Вантажівка, Седан)

Користувач вибирає "Седан". Відповідні підписки - 2 і 2.

Як бачите, до моменту вибору користувача, наприклад, "Ford" "Седан" "Тельця", ви побачите, що вам потрібно прочитати лише рядки 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          -'   -

Він використовується точно так само, як і множинна версія файлу, за винятком того, що вам потрібен фіктивний перший рядок, щоб містити перший діапазон підписів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.