ここにはいくつかの良い答えがあります。私はいくつかのコードを書いてテストしました。
まず、要件の単純な実装を示します。
import pprint
t = [
[ 23, None, 'Delhi', None, 0.33 ],
[ None, 'M', 'Mumbai', None, 0.78 ],
[ None, None, None, 'Hindu', 0.23 ],
[ 34, 'F', 'Chennai', None, 0.33 ],
]
rlen = len(t[0])
# None may require special handling
m = [23, 'M', 'Delhi', 'Hindu', None]
a = [[] for i in range(rlen+1)]
for r in t:
s = sum([1 for i in range(rlen) if r[i] == m[i]])
if 0 < s:
a[s].append(r)
# Print rows from least matching to most matching (easy to reverse)
rtable = [row for n in a for row in n]
pprint.pprint(rtable)
問題は、各行をスキャンして各要素の値を確認することです。最後に並べ替える必要がないように、一致する可能性のあるカウントごとに個別のリストを保持してから、リストのリストをフラット化して最終結果を出します。これは、テーブルのサイズに比べて約O(n)のパフォーマンスを期待します。一致する数が多い場合は、さらに悪くなります(大きな結果リストの作成は、O(n)よりも遅くなり、O(n ^ 2)に近づきます。最悪の場合)。
テーブルにインデックスを付けると、処理を高速化できます。列ごとに1つのdictを使用し、セットを使用して列を組み合わせることができます。
from collections import defaultdict
import pprint
# data table
TABLE = [
[ 23, None, 'Delhi', None, 0.33 ],
[ None, 'M', 'Mumbai', None, 0.78 ],
[ None, None, None, 'Hindu', 0.23 ],
[ 34, 'F', 'Chennai', None, 0.33 ],
]
# The index is a list of dicts, cdictlist.
# cdictlist is indexed by column number to get the column dict.
# The column dict's key is the data value of the column
def BuildIndex(table):
rlen = len(table[0])
rrange = range(rlen)
cdictlist = [defaultdict(set) for i in range(rlen+1)]
for ir in range(len(table)):
r = table[ir]
for ic in rrange:
f = r[ic]
cdictlist[ic][f].add(ir)
return cdictlist
def multisearch(table, match, cdictlist):
# rcounts is row counts, number of times columns have matched for a row
rccounts = defaultdict(int)
#rset is the result set, set of row indexes returned for this search
rset = set()
for ic in range(len(table[0])):
cset = cdictlist[ic].get(match[ic], set())
rset = rset.union(cset)
for i in cset:
rccounts[i] += 1
# sort the list by column match count, original row index
l = sorted((v,k) for (k,v) in rccounts.iteritems())
# return list of rows, for each row we return (count, index, raw data)
lr = [ [l[i][0], l[i][1]] + table[l[i][1]] for i in range(len(l)) ]
return lr
def main():
cdictlist = BuildIndex(TABLE)
# None may require special handling
match = [23, 'M', 'Delhi', 'Hindu', None]
lr = multisearch(TABLE, match, cdictlist)
pprint.pprint(lr)
if __name__ == '__main__':
main()
パフォーマンスは、テーブルのサイズではなく、返されるレコードの数によって異なります。和集合の操作は、多数の一致に対してすぐに問題になります。また、いずれかのフィールドが一致し、フィールドの例の1つがGenderである場合、レコードは一致するため、少なくとも行の半分が返されることを期待する必要があります。
すべての列を一致させる必要がある場合、このアプローチははるかにうまく機能します。返されないレコードのセットを構築し(セットの共通部分を使用)、それらのレコードを除外することで、これを改善できる可能性があります。