2017-07-14 106 views
2

的关键我有一个列表传递函数来排序功能

lis = [ [0, 1], [1, -1], [1, 0] ] 

我想根据特定条件来排序。我想使用一个逻辑,只要lis[i][0]等于lis[i + 1][0],交换元素。类似于

在上面的列表中,第二个和第三个元素是[1, -1][1, 0],其中lis[i][0] == lis[i + 1][0]。所以,我会掉它,使得我的新名单变得

lis = [ [0, 1], [1, 0], [1, -1] ] 

这是我的函数:

def sortList(lis3): 
    for i in range(0, len(lis3) - 1): 
     for j in range(i + 1, len(lis3)): 
      if lis3[i][0] == lis3[j][0]: 
       lis3[i], lis3[j] = lis3[j], lis3[i] 

我想这个函数传递给列表的sort方法,使得其根据本排序逻辑:

我想这样做,但不工作:

lis.sort(key=sortList) 

^h我可以让这个功能在sort方法中工作吗?

+1

这与排序不一样...排序必须是全局属性,而不是直接依赖于邻居。 (如何使用合并排序?或其他排序算法?结果将如何?[python使用[timsort](https://en.wikipedia.org/wiki/Timsort)])。 –

+0

@hiroprotagonist那么有没有另一种方法可以做到这一点? –

+3

这个问题并没有很好的定义......'lst = [(0,0),(0,1),(0,2)]':结果是什么?您在列表中迭代的次数和次数?你什么时候完成? –

回答

1

正如在其他答案中已经说过,它不可能(或至少不平凡),使其与sorted工作。然而,你可以不用任何的排序,只是基于第一个元素收集指标:

from collections import defaultdict 

lis = [[0, 1], [1, -1], [1, 0]] 

d_idx = defaultdict(list) 

for idx, item in enumerate(lis): 
    d_idx[item[0]].append(idx) 

然后创建一个“结果”列表中,只是扭转具有相同的第一元素中的所有元素的索引:

res = [None]*len(lis) 

for _, value in d_idx.items(): 
    for orig_idx, target_idx in zip(value, reversed(value)): 
     res[target_idx] = lis[orig_idx] 

其中给出的res

>>> res 
[[0, 1], [1, 0], [1, -1]] 

注意:它可能不是所期望的行为,以“反向”与相同的第一元素中的元素。因为@hiro protagonist noted in the comments

这个问题没有很好的定义...... lst = [(0,0), (0,1), (0,2)]:结果是什么?您在列表中迭代的次数和次数?你什么时候完成?

的情况下,你需要一个不同的行为哪些元素应该被分配到哪个位置,你(可能)只需要更改for orig_idx, target_idx in zip(value, reversed(value)):线,有应用所需的操作。


进一步的优点是,这种方法只具有O(n)运行时行为而sort具有O(n*log(n))(平均)运行时。所以它可能会更快。

+1

cool!所以我最好不要使用排序功能,并尝试以你的方式做到这一点:) –

0

python排序方法将对列表进行排序,仅使用项目之间的<比较。您必须传递一个函数,将每个元素映射到可能与其他映射元素进行比较的某个元素,以便“小于”关系提供所需的结果。

但是,您的规则并未定义任何类型的关系,可以根据元素a,b的a < b来描述。它只是定义相邻元素之间的关系,它甚至不是一个稳定的关系:如果a < b因此您交换这两个项目,那么它立即成为b < a的情况。

简而言之,lis.sort()是完全不适合这项任务。

2

您不能使它与list.sortsorted可靠地工作。问题在于这些函数背后的排序算法并不能保证哪些元素被比较或者没有(它只是说结果将被排序)。对于list.sortsorted可以可靠地工作,您需要keytotal ordering relation,这是您的功能不提供的。

此外key应该是一个功能,将一个元素转换为“应该比较的属性”,它确实将列表的每个元素传递给key函数而不是总列表(事实上在CPython中列表为空而你sort它,所以它根本无法工作)。执行此排序

1

的一种方法是使用cmp参数sorted(使用functools.cmp_to_key为Python 3)和返回-1时在两个子列表的索引0的项目比较等于或否则为0。这是假设的项目是在对和是连续的,所以它不是一个真正的详尽的梳理,只有一个的hackish的方式来交换你的项目:

lis = [ [0, 1], [1, -1], [1, 0], [2, 5], [2, 6]] 

print sorted(lis, cmp=lambda x, y: -1 if x[0]==y[0] else 0) 
# [[0, 1], [1, 0], [1, -1], [2, 6], [2, 5]] 

然而,分拣变得暧昧两个以上的项目在索引0处具有相同的值,或者项目不是连续的


OTOH,您可以循环访问您的列表并交换符合条件的成对连续项目。无需应用分类!

+1

,并不保证所有项目都是相互比较的。所以它可能工作或不工作取决于哪些项目进行比较。 – MSeifert

+0

@Moses你可以在python 3中显示相同的实现吗?我尝试使用functools.cmp_to_key但弹出错误。 –

+0

@SouvikRay'sorted(lis,key = functools.cmp_to_key(lambda x,y:-1 if x [0] == y [0] else 0))' –