2017-07-08 5 views
2

異なる入力に対して同じことを返すことができる効率的な "switch"文を書くには? Pythonで
単純なスイッチは、次のように辞書を使用して実装することができます。別名を持つPython switch文

def switch(s): 
    case = {'phone': '123 456 789', 'website': 'www.example.com'} 
    return case[s] 

この1一定のアクセス時間を持っている、しかし私は、すなわちswitch('website')は値を複製することなく、switch('site')などと同じものを返しますエイリアスを使用する場合、すなわち使用しない
case = {'website': 'www.example.com, 'site': 'www.example.com}
使用することができますどのような は、次のとおりです。

def switch(s): 
    case = {('telephone', 'number', 'phone'): '123 456 789', 
      ('website', 'site'): 'www.example.com'} 
    for key, value in case.items(): 
     if s in key: 
      return value 

しかし、このアプローチは、線形アクセスよりも悪化しています時間。
それは

def switch(s): 
    case = ['123 456 789', 'www.example.com'] 
    aliases = {'telephone': 0, 'number': 0, 'phone': 0, 
       'website': 1, 'site': 1} 
    return case[aliases[s]] 

を使用することにより、一定にすることができるが、その後、私はソートの値を複製だと場合には、私はすべての答えを削除することを決定 、私はaliasesを編集する必要が 'および/またはcaseの戻り

は番目です(私はもはや'123 456 789'を返すようにしたい場合、私はcaseからそれを削除し、aliases['website']aliases['site']リターン0 ORはcaseの第一のセルにダミーの値を残したり、case辞書を作るようにaliasesを変更する必要がない)の値そのようなステートメントを書く良い方法はありますか?

+0

私は第2の例が非線形時間を有するとは思わない。それはあなたのスイッチのプールはどれくらいの大きさですか? – Uriel

+0

2番目の例では、直線的にすべてのキーを調べ、各キー内で文字列がこのキーの内側にあるかどうかを確認します。これも効率的ではありません。 – Szymon

+0

どのようにそう? 2つの最悪の場合と最良の場合を取ることができます:すべてのタプルキーの長さは1です。次に、O(n)を取得します。単一のタプルキーがあります。 O(log(n))である。 – Uriel

答えて

2

は、リンクされたハッシュマップのアプローチを使用することができます。

def switch(s): 
    alias = {'telephone': 1, 'number': 1, 'phone': 1, 
      'website': 2, 'site': 2} 
    case = {1: '123 456 789', 2: 'www.example.com'} 
    return case[alias[s]] 

そのようにあなたがO(1)検索時間を維持しています。

もちろん、実際のデータでは、aliascaseマップの構築を自動化したいと思うでしょうが、それはやや簡単です。

更新/削除は、簡単にdictの更新/削除になるので、やはり簡単にする必要があります。

また、新しい値を簡単に挿入するには、数字の代わりにUUID4(またはその他のランダム値)を使用できます。私は単にあなたの元case辞書以外にアイデンティティエイリアスなしaliases辞書を使用してgetを使用して潜在的な別名をチェックするでしょう

+0

これは私の3番目の例で使用したものです。 – Szymon

+2

いいえ、あなたは 'alias'に' list'を使いました。 'dict'では、値を更新(削除)する際に問題はありません。 – randomir

+0

右下の3番目の例私はそれを修正する可能性のある修正の1つとして書きました。 "または" case'辞書を作る " – Szymon

1

:あなたは(ないcaseに値を複製する必要はありませんその方法を

def switch(s): 
    case = {'phone': '123 456 789', 'website': 'www.example.com'} 
    aliases = {'telephone': 'phone', 'number': 'phone', 'site': 'website'} 
    return case[aliases.get(s, s)] # check if it's an alias or use the input as-is 

aliasにはありません)。あなたの質問に

0

あなたが言う:

私は別名を使用したい、つまりswitch('website')は値

を複製せずに switch('site')などと同じものを返します。私は、重複値についてのあなたの懸念があると思いますあなたはそのアプローチを拒否すべきではありません。同じ文字列値を持つ追加の辞書エントリを追加することは問題ではないはずです。問題を解決するのは自然な方法です。必要がない場合は、余分な間接レイヤーを使用してコードを複雑化しないでください。

私は、同じ値が辞書に何度も保存されるため、メモリ使用量が増加する可能性があると考えています。しかし、ほとんどの場合、複数の別々の同一の文字列を持つことはなく、同じ文字列オブジェクトへの複数の参照を持つことになります。文字列は不変なので、Pythonは同じ内容の別の独立した文字列を作成する必要があると思われるときに、既存のオブジェクトへの参照を置き換えることがあります。

あなた自身でテストできます。それぞれのidをテストし、その後、値として複数の同一の文字列リテラルで辞書を作成してみてください:私のシステムで

d = {"a": "foo", "b": "foo", "c": "foo"} 

for val in d.values(): 
    print(id(val)) 

これはid sがすべて同じであると言われます。私は、同時にコンパイルされた複数の同一の文字列リテラルは、常に単一の文字列オブジェクトへの複数の参照に変換されると考えています。状況によっては、 "interning"という文字列のおかげで、特定の内容(一般的には識別子のように見えるもの)を含むすべての文字列は、プログラムのどこでも共有されます。しかし、あなたはおそらく詳細についてあまり気にする必要はありません。実現する重要なことは、複製された文字列がおそらく大量のメモリを使用しないことです。

すべてのエイリアスを1つの辞書に追加することに異議を唱える理由はありません。それは自然な解決策なので、私はそれをやります。後でメモリ使用量が問題になる場合は、重複したオブジェクトではなく、重複して参照されていることを再確認するように辞書を再訪するかもしれませんが、深刻なプログラムの規模には問題はないでしょう。

使いやすく理解しやすいコードが重要です。

あなたの主な関心事が繰り返されていないとコメントしたので、リテラルとして直接行うのではなく、コードを使用してわずかに冗長性の低いデータ構造を変換することができます。例えば

は、次のコードは、リストをオンにする辞書理解を使用していることを簡単に検索辞書にペアアップそれらの値を持つエイリアスのサブリストを:

_data = [  # contains (alias_list, value) 2-tuples 
    (['telephone', 'number', 'phone'], '123 456 789'), 
    (['website', 'site'], 'www.example.com'), 
] 

case = {alias: value for aliases, value in _data for alias in aliases} 

あなたはおそらくどこにそれをどこかにこのコードを入れたいですあなたのswitch関数が呼び出されるたびに辞書の理解を実行するのではなく、一度だけ実行されます(トップレベルやクラスやインスタンス変数など)。ディクショナリは変更可能であるため、Pythonは呼び出しごとに同じdictオブジェクトを使用することはできません(常に同じ値でも)。

+0

あなたが言ったように、Pythonはおそらくそれを最適化する可能性が高いため、私の心配は実行時のメモリ使用量ではありません。私の関心事は「1つの値を変更する必要がある場合はどうなりますか?」です。それから、すべてのキーの値を変更する必要がありますが、ファイルに保存されるため、値を変更するはずのキーがいくつか見逃されるのは簡単です。 – Szymon

+1

エイリアスのリストとその値(例えば、2番目の例のデータの種類)を含むシーケンスから辞書を生成する数行のコードを書くのはかなり簡単です。私はそれを私の答えに加えます。 – Blckknght