このデータを保存する最も効率的な方法は何ですか?


9

私はいくつかの古いVBコードの書き換えを担当しています。私はそれがどのように機能するかを理解していますが、彼らがしたことを行うためのはるかに効率的な方法があるように感じます。それが何なのかわからない。これは、データ要件の点で私がする必要があるものと本当に似ている不自然な例です。

ユーザーは、GUIで車のメーカー、メーカー、モデル、色を選択する必要があります。次のような大きなテキストファイルがあります。

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.

したがって、最初の選択がスバルである場合、スバルはいずれもトラックではないため、2番目のボックス(メーカー)にはトラックを選択するオプションはありません。同様に、フォード、セダン、トーラスを選択した場合、最後のボックス(色)には青を選択するオプションが表示されませ。または黒。または、赤、緑、白以外のもの。

私の前にコードを書いた人々はこれを思いつきました(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

アルゴリズムレベルでも構文レベルでも、それは恐ろしいだけだと思います。1つは、正しく実行された場合に数行を読み取るだけでよい場合に、ファイル全体を解析することです。これをさらに非効率的にするために、私の実際のデータには、4つではなく6つの選択肢があります。これは、データの重複の量を考えると、必要以上のデータを格納することにもなります。

ファイルにデータを保存する別の方法、またはgetValidOptions関数をより美しく効率的にするためにデータを解析する別の方法を探しています。これを行う方法はありますか?


2
データベースを使用しないのはなぜですか?
TulainsCórdova15年

回答:


6

私が読んだ他のすべての回答は、ソフトウェア開発の2つの非常に基本的なルールを無視しているようです。

  • まず要件を明確にします(特にパフォーマンスとストレージの要件)

  • シンプルに、愚かにしてください(KISSを参照)

「テキストファイルが大きい」と書いてありましたが、大きすぎないので、直感以外はサイズに問題はないと思います。したがって、ファイルのロードに実際にはそれほど時間がかからず、IT部門または他の誰かが無駄なディスク領域について不平を言っておらず、誰もファイルの維持に問題があることについて不平を言っていない場合は、ファイル形式をそのままにしてください-過小評価しないでくださいシンプルさの価値。

アルゴリズムの効率についても不満がありますが、これは実際にはそれほど効率的ではありませんが、非常に大きな利点が1つあります。したがって、十分に効率的である限り、時期尚早の最適化を適用しないでください。

それでは、プログラムが十分に高速に動作すると仮定しましょう。最初に確認する必要があるのは、単純さとDRY原理の観点からコードをどのように改善できるかということです。そして、現在のコードはDRYではないので、それは確かに改善すべき点です。あなたの例では、「上位レベル」のオプションが現在の行と一致する場合、ほぼ同じコードブロックテストが4回表示されます。これにより、同じ種類の「追加」呼び出しが4回発生します(実際のコードでは、繰り返しが発生します)あなたが書いたように、少なくとも6回)。数値の選択レベルを導入するか、すでに選択されているオプションを順序付けられたリストで渡すことで、これを簡単に回避できます。あなたの疑似コードを使用すると、これは

# 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複数回呼び出す必要があることは明らかであるため(少なくともレベルごとに1回)、最適化を1つだけ適用することをお勧めします(これがまだ当てはまらない場合):getLine関数がメインメモリからデータをプルし、ディスクからファイルを何度も読み取ります。


numRowsループの前に「level = selectedOptions.size()」を移動する必要があります。
AI Breveleri 2015

6

さて、あなたが持っているデータはツリーのような構造をしており、各メーカーにはモデルのツリーがあり、各モデルには色(など)があります。

したがって、このデータのプロセスを2つのステップで分離できます。

  1. テキストファイルを更新したら、そのファイルを処理してツリー構造に変換する必要があります。
  2. アプリケーションをロードするときは、ツリー構造のみをロードします。

ツリー構造は、いわゆるハッシュ連想配列、またはJava、PHP、Javascript、Pythonなどの言語の辞書で実装できます。この構造により、以下が得られます。

  • 最初のキーはメーカーです。
  • それらの値は、各キーがモデルである別のハッシュまたは辞書です。
  • それらの値は色です。または、3番目のレベルをキーに保持し、4番目のレベルを値として保持する別の構造。
  • 等々...

プログラミング言語に応じて、これはより速くまたはより遅く実装することができます。例えば:

  • C#:ツリー構造1を実装し、シリアル化可能としてマークできます。
  • VB.Net:1つのアプリケーションでツリー構造を生成し、それをファイルにシリアル化できます。
    • このため、のようなもの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実装に非常に多くの時間を費やすのは価値があります。
James

現時点では私はC#の専門家ではありませんが、少なくともJavaやPHPなどの他の言語では、各キーに値として別のディクショナリを設定できる、ある種のディクショナリを作成できます。
ニコラス

回答を更新しました。ハッシュや辞書の代替案についてどう思うか見てください。興味深い記事の参考文献も追加しました。
ニコラス

3

データを保存する簡単な方法の1つは、SQLiteデータベースにデータを格納することです。SQLiteは、ほとんどのSQLデータベースとは異なり、アプリケーションファイル形式としての使用に適しています。このアプローチにはいくつかの利点があります。

  1. シリアライザやデシリアライザをコーディングする必要はありません。
  2. ファイルは、多数の既存のプログラムで編集および照会できます。
  3. 質問で言及する条件付きの乱雑さは回避されます。ドロップダウンを制限するには、各列に対して単純なwhere句を生成します(例:)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

最初のインデックスを作成するには、ファイルの最初の3つのフィールドの一意の組み合わせごとにレコードを作成します。各レコードに、その組み合わせが表示される最初と最後の行番号を格納します。

--| 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

2番目のインデックスは、最初のインデックスの最初の2つのフィールドを使用して、同様に構築されます。

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

そして3番目は、この場合の最上位のインデックスです。

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

概念を説明しすぎだと思いますが、一般的には、最後のフィールドを削除して重複レコードを排除することにより、インデックスを作成します。

一部の冗長データを排除することで、ファイルストレージ要件をさらに削減できます。

たとえば、各インデックスレコードの「最初の」添え字は常に、前のレコードの「最後の」添え字より1つ多いか、前のレコードがない場合はゼロです。したがって、「最初の」添え字を格納する必要はありません。説明のために、下に置いておきます。

また、各レコードの最後のフィールドのみを使用して選択リストに入力するため、他のフィールドを格納する必要はありません。

インデックスカスケードの最小レンディションは、次のようになります。ティック 'は、実際にはファイルに保存されていない数値を示します。

--| 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です。

2番目の選択リストに、0〜1行目を入力しfile1.datます。(トラック、セダン)

ユーザーは「セダン」を選択します。対応する添え字は2と2です。

ご覧のように、ユーザーが「フォード」「セダン」「トーラス」などをfile3.dat選択するまでに、4番目の選択リストを満たすために6〜8行目のみを読み取る必要があることがわかります。

長い説明で申し訳ありませんが、ここでは非常に遅く、短い説明を書く時間はありません。

追加:さらに考えると、ファイルを1つに連結できます。

--| 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          -'   -

これは、最初の添え字範囲を含めるためのダミーの最初の行が必要であることを除いて、複数ファイルバージョンとまったく同じように使用されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.