我对Python完全陌生,在尝试各种随机的点点滴滴时,我发现了一个问题,我相信我已经“解决了”,但代码并没有感觉正确 - 我强烈怀疑会有更好的方法来获得理想的结果。
仅供参考 - 我在Windows上使用的是最新版本的Python 3。
简单地说,我正在做的是对一对对的列表进行排序,这样包含最少对中出现的元素的对被排序到前面。
这些对的格式为[i,j]
0 <= i <= j < n
,其中n
是元素的已知最大值。列表中没有重复的对。
元素i
的计数是表单[i,j]
,[j,i]
和[i,i]
中j
的对数(不是对元素)的简单计数1}}是导致有效对的任何值。
在排序后的结果中,如果 [i,j]
或[k,l]
和count(i) < count(k)
(count(i) == count(k)
count(j) < count(l)
,count(j) == count(l)
对应出现在[i,j]
对之前1}}这两个可以按任意顺序排列 - 我并不担心这种类型是稳定的,虽然会是奖金。)
在排序后的结果中,如果是,则[k,l]
对应出现在min(count(i),count(j)) < min(count(k),count(l))
对之前
min(count(i),count(j)) == min(count(k),count(l))
或
max(count(i),count(j)) < max(count(k),count(l))
和[0,1]
。
换句话说,如果该对为1
且0
的计数为1,但input [[0,0],[1,2],[1,4],[2,2],[2,3],[3,3],[3,4]]
的计数为400,则该对仍应处于(或至少非常接近)列表的前面 - 他们需要按对中最不频繁的元素进行排序。
这是我建立的一个人为的例子:
0: 1 [0,0]
1: 2 [1,2],[1,4]
2: 3 [1,2],[2,2],[2,3]
3: 3 [2,3],[3,3],[3,4]
4: 2 [1,4],[3,4]
以下是单个元素计数及其来源对:
output: [[0,0],[1,4],[1,2],[3,4],[2,2],[2,3],[3,3]]
scores: 1 1-2 1-3 2-3 3 3 3
这是结果,以及配对分数:
0
在这里,1
的计数为1(它出现在一个对中,虽然是两次),所以首先出现。 [1,4]
计数为2,因此在[1,2]
之前显示为4
,因为2
的计数为2,#my implementation uncommented to reduce post size, see history for comments
def sortPairList( data , n ):
count = []
for i in range(0,n):
count.append( 0 )
#count up the data
for p in data:
count[p[0]] += 1
if p[1] != p[0]:
count[p[1]] += 1
maxcount = 0
for i in range(0,n):
if count[i] > maxcount:
maxcount = count[i]
def elementFrequency(p):
if count[ p[0] ] < count[ p[1] ]:
return count[ p[0] ] + float(count[ p[1] ]) / (maxcount+1)
else:
return count[ p[1] ] + float(count[ p[0] ]) / (maxcount+1)
data.sort( key=elementFrequency )
的计数为3,等等。
如上所述,我相信这种说法可以准确地发挥作用,但它只是觉得必须有更好的方法去做这件事。无论如何,这是我到目前为止所得到的:
input: [[0,0],[0,3],[0,5],[0,7],[1,1],[1,2],[1,8],[2,4],[2,5],[3,4],[3,5],[3,9],[4,4],[4,7],[4,8],[6,8],[7,7],[7,9],[8,9]]
expected: [[6,8],[1,1],[1,2],[2,5],[0,5],[1,8],[3,5],[3,9],[7,9],[8,9],[2,4],[0,0],[0,3],[0,7],[7,7],[3,4],[4,7],[4,8],[4,4]]
有关更“Python”方式的任何建议吗?
或者我目前的尝试出了什么问题?
{{1}}
答案 0 :(得分:4)
我可能会使用Counter(需要Python≥2.7或≥3.1)来计算。
from collections import Counter
from itertools import chain
def sortPairList2(data):
tally = Counter(chain(*map(set, data)))
data.sort(key=lambda x: sorted(tally[i] for i in x))
请注意:
您可以创建an anonymous function with lambda
。例如,
>>> c = 4
>>> a = lambda p: p - c
>>> a(7)
3
排序键不必是数字。任何可比较的东西都可以用作关键功能的返回值。在我的代码中,list
用于排序。
Python中有许多比较简单的习惯用法。
count
而不是该循环来初始化count = [0] * n
。max
function获取maxcount
。 maxcount = max(count)
List comprehension在Python中经常使用。如果您的目标是将迭代变换为另一个迭代,则更喜欢理解循环。
答案 1 :(得分:1)
>>> n = 4
>>> freqs = {i: sum(i in j for j in inp) for i in range(n+1)}
>>> def key(x):
a, b = x
return min(freqs[a], freqs[b]), max(freqs[a], freqs[b])
>>> sorted(inp, key=key)
P.S。请注意,input
是变量的错误名称,因为它会内置阴影。
答案 2 :(得分:0)
当KennyTM解决方案有效时,我试图自己做。
我的解决方案预先计算频率并将其存储在str(n)
是关键字典的字典中。将Python2中已知的比较函数更改为与Python3一起使用的密钥时遇到了一些麻烦,但我在ActiveState code找到了食谱
item_cnt = {}
def icount(n):
return item_cnt[str(n)]
def add_item(n):
sn = str(n)
try:
item_cnt[sn] += 1
except KeyError:
item_cnt[sn] = 1
# sort callback
def cmp_items(ij, kl):
i, j = ij
k, l = kl
if icount(i) < icount(k) or icount(i) == icount(k) and icount(j) < icount(l):
return -1
return 1
input = [[0,0],[1,2],[1,4],[2,2],[2,3],[3,3],[3,4]]
# count all items
for (i, j) in input:
add_item(i)
add_item(j)
# works with Python 2.x
#input.sort(cmp_items)
# works with Python2.6 and Python 3.x
# to convert compare function to key look at:
# http://code.activestate.com/recipes/576653-convert-a-cmp-function-to-a-key-function/
input.sort(key=cmp_to_key(cmp_items))
print(input)
答案 3 :(得分:0)
与KennyTM的解决方案类似,但对于Python 2.5或更高版本:
import collections
def sort_by_occurence(sequences):
tally = collections.defaultdict(int)
for sequence in sequences:
for item in sequence:
tally[item] += 1
sequences.sort(key=lambda x:map(tally.get, x))
pair_list = [[0,0],[1,2],[1,4],[2,2],[2,3],[3,3],[3,4]]
sort_by_occurence(pair_list)
print pair_list