2016-08-31 7 views
3

オブジェクトのリストをサブリストに分割したいのですが、同じ属性/特性を持つオブジェクトは同じサブリストにとどまります。次のように私たちは、その長さに基づいて文字列を分離したいPython:オブジェクトの特性や属性を使ってオブジェクトのリストをグループ化する方法は?

["This", "is", "a", "sentence", "of", "seven", "words"] 

[['sentence'], ['a'], ['is', 'of'], ['This'], ['seven', 'words']] 

私は現在、思い付くプログラムこの

されているとし

我々は、文字列のリストを持っています

sentence = ["This", "is", "a", "sentence", "of", "seven", "words"] 
word_len_dict = {} 
for word in sentence: 
    if len(word) not in word_len_dict.keys(): 
     word_len_dict[len(word)] = [word] 
    else: 
     word_len_dict[len(word)].append(word) 


print word_len_dict.values() 

これを達成するより良い方法があるかどうかを知りたいのですが?

+0

どのようにすればよいですか?私は個人的にその実装に問題はないと思う(それが動作すると仮定して、私はそれをチェックしていない) – FamousJameous

+2

データがソートされていないので、標準的な方法を見つけた。代わりに 'word_len_dict = defaultdict(list)'を使うことができますので、キーがすでに存在する場合はテストを続ける必要はありません。あなたのデータがすでにソートされている場合は、 'itertools.groupby()'を使います。 –

+0

'dict.setdefault()'を使うと、 'defaultdict'を不要にすることがよくあります。 –

答えて

5

itertools.groupby()をご覧ください。あなたのリストは最初にソートされなければならないことに注意してください(はあなたのメソッドOPよりも高価です)。

>>> from itertools import groupby 
>>> l = ["This", "is", "a", "sentence", "of", "seven", "words"] 
>>> print [list(g[1]) for g in groupby(sorted(l, key=len), len)] 
[['a'], ['is', 'of'], ['This'], ['seven', 'words'], ['sentence']] 

か、辞書たい場合は - >

>>> {k:list(g) for k, g in groupby(sorted(l, key=len), len)} 
{8: ['sentence'], 1: ['a'], 2: ['is', 'of'], 4: ['This'], 5: ['seven', 'words']} 
+1

ソートはO(NlogN)操作で行われます。辞書を使用したグループ化はO(N)です。データが既にソートされている場合にのみ、 'groupby'を使用してください。そうでない場合は、OPがすでに考案している方法に固執します(グループ化するアイテムの数が増えると特に効果があります)。 –

+0

ああ、私は完全に同意します。それが私がそれを書き留めた理由です。 OPの方法には何も問題はありません。スピードが問題ではない/彼のデータは既にソートされていれば私は代替案を提供すると思っていました。 – ospahiu

2

defaultdict(list)を使用すると、キーの存在チェックを省略することができます。

from collections import defaultdict 

word_len_dict = defaultdict(list) 

for word in sentence: 
    word_len_dict[len(word)].append(word) 
0

を今私はあなたがコンパクトなコードよりよく検討しない限り、これはどのような方法で優れているつもりはありません。あなたのバージョン(これは非常にokです)は、はるかに読みやすくメンテナンスが容易です。

list_ = ["This", "is", "a", "sentence", "of", "seven", "words"] 

# for python 2 filter returns() a list 
result = filter(None,[[x for x in list_ if len(x) == i] for i in range(len(max(list_, key=lambda y: len(y)))+1)]) 

# for python 3 filter() returns an iterator 
result = list(filter(None,[[x for x in list_ if len(x) == i] for i in range(len(max(list_, key=lambda y: len(y)))+1)])) 
1

itertools.groupbyのドキュメントが正確に何をしたいと一致する例があります。

keyfunc = lambda x: len(x) 
data = ["This", "is", "a", "sentence", "of", "seven", "words"] 
data = sorted(data, key=keyfunc) 
groups = [] 
for k, g in groupby(data, keyfunc): 
    groups.append(list(g)) 
print groups 
0
sentence = ["This", "is", "a", "sentence", "of", "seven", "words"] 
getLength = sorted(list(set([len(data) for data in sentence]))) 

result = [] 

for length in getLength: 
    result.append([data for data in sentence if length == len(data)]) 

print(result) 
0

あなただけsetdefault機能を使って、辞書でこれを行うことができます。それが存在し、単に取得していない場合は、あなたの辞書にキーlen(word)に設定されているん何setdefault

sentence = ["This", "is", "a", "sentence", "of", "seven", "words"] 
word_len_dict = {} 
for word in sentence: 
    word_len_dict.setdefault(len(word), []).append(word) 

をその場合の値。 setdefaultの2番目の引数は、そのキーと共に保存するデフォルト値です。

キーがすでに存在する場合、setdefaultに渡されるデフォルト値は、古い値に置き換えられないことに注意することが重要です。これにより、各リストは1回だけ作成され、その後は同じリストがsetdefaultによって検索されます。あなたの目標は、より少ない行でそれを行うのであれば

0

、常に内包表記があります:あなたはちょうどすぐに何かをコーディングする場合

data = ["This", "is", "a", "sentence", "of", "seven", "words"] 
# Get all unique length values 
unique_length_vals = set([len(word) for word in data]) 
# Get lists of same-length words 
res = [filter(lambda x: len(x) == lval, data) for lval in unique_length_vals] 

それはあまり明確ではなく、役に立つかもしれません。

関連する問題