Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python:洗牌列表,但保持某些元素冻结_Python_Python 2.7 - Fatal编程技术网

Python:洗牌列表,但保持某些元素冻结

Python:洗牌列表,但保持某些元素冻结,python,python-2.7,Python,Python 2.7,我有这样一个问题: 有一个类CAnswer的元素列表(无需描述该类),我需要对其进行洗牌,但有一个限制-列表中的一些元素将CAnswer.freeze设置为True,这些元素不能被洗牌,而是保持在其原始位置。比如说,对于给定的列表: [a, b, c, d, e, f] 如果所有元素都是CAnswer,但c.freeze==True,而其他元素则是freeze==False,则可能的结果可能是: [e, a, c, f, b, d] 所以索引为2的元素仍然在其位置上 实现它的最佳算法是什么

我有这样一个问题:

有一个类
CAnswer
的元素列表(无需描述该类),我需要对其进行洗牌,但有一个限制-列表中的一些元素将
CAnswer.freeze
设置为
True
,这些元素不能被洗牌,而是保持在其原始位置。比如说,对于给定的列表:

[a, b, c, d, e, f]
如果所有元素都是
CAnswer
,但
c.freeze==True
,而其他元素则是
freeze==False
,则可能的结果可能是:

[e, a, c, f, b, d]
所以索引为2的元素仍然在其位置上

实现它的最佳算法是什么

提前感谢:)

一个解决方案:

def fixed_shuffle(lst):
    unfrozen_indices, unfrozen_subset = zip(*[(i, e) for i, e in enumerate(lst)
                                            if not e.freeze])
    unfrozen_indices = list(unfrozen_indices)
    random.shuffle(unfrozen_indices)
    for i, e in zip(unfrozen_indices, unfrozen_subset):
        lst[i] = e
# memorize position of fixed elements
fixed = [(pos, item) for (pos,item) in enumerate(items) if item.freeze]
# shuffle list
random.shuffle(items)
# swap fixed elements back to their original position
for pos, item in fixed:
    index = items.index(item)
    items[pos], items[index] = items[index], items[pos]
注意:如果
lst
是一个列表,而不是一个常规列表,这可能会简单一些:

def fixed_shuffle_numpy(lst):
    unfrozen_indices = [i for i, e in enumerate(lst) if not e.freeze]
    unfrozen_set = lst[unfrozen_indices]
    random.shuffle(unfrozen_set)
    lst[unfrozen_indices] = unfrozen_set
其用法示例如下:

class CAnswer:
    def __init__(self, x, freeze=False):
        self.x = x
        self.freeze = freeze

    def __cmp__(self, other):
        return self.x.__cmp__(other.x)

    def __repr__(self):
        return "<CAnswer: %s>" % self.x


lst = [CAnswer(3), CAnswer(2), CAnswer(0, True), CAnswer(1), CAnswer(5),
       CAnswer(9, True), CAnswer(4)]

fixed_shuffle(lst)
类CAnswer:
定义初始化(self,x,freeze=False):
self.x=x
self.freeze=冻结
定义cmp(自身、其他):
返回self.x.\uuuu cmp\uuuu(其他.x)
定义报告(自我):
返回“%self.x”
lst=[CAnswer(3),CAnswer(2),CAnswer(0,真),CAnswer(1),CAnswer(5),
CAnswer(9,正确),CAnswer(4)]
修正了洗牌(lst)
另一种解决方案:

def fixed_shuffle(lst):
    unfrozen_indices, unfrozen_subset = zip(*[(i, e) for i, e in enumerate(lst)
                                            if not e.freeze])
    unfrozen_indices = list(unfrozen_indices)
    random.shuffle(unfrozen_indices)
    for i, e in zip(unfrozen_indices, unfrozen_subset):
        lst[i] = e
# memorize position of fixed elements
fixed = [(pos, item) for (pos,item) in enumerate(items) if item.freeze]
# shuffle list
random.shuffle(items)
# swap fixed elements back to their original position
for pos, item in fixed:
    index = items.index(item)
    items[pos], items[index] = items[index], items[pos]

在线性时间中,恒定空间使用:


过度工程化的解决方案:创建一个包含未冻结元素索引并模拟列表的包装类,并确保setter写入原始列表:

class IndexedFilterList:
    def __init__(self, originalList, filterFunc):
        self.originalList = originalList
        self.indexes = [i for i, x in enumerate(originalList) if filterFunc(x)]

    def __len__(self):
        return len(self.indexes)

    def __getitem__(self, i):
        return self.originalList[self.indexes[i]]

    def __setitem__(self, i, value):
        self.originalList[self.indexes[i]] = value
并致电:

random.shuffle(IndexedFilterList(mylist, lambda c: not c.freeze))

使用列表具有快速删除和插入功能的事实:

  • 枚举固定元素并复制它们及其索引
  • 从列表中删除固定元素
  • 洗牌剩余子集
  • 把固定元件放回去
有关更一般的解决方案,请参阅

这将使用具有内存开销的就地操作,内存开销取决于列表中固定元素的数量。在时间上是线性的。
shuffle\u subset
的可能实现:

#!/usr/bin/env python
"""Shuffle elements in a list, except for a sub-set of the elments.

The sub-set are those elements that should retain their position in
the list.  Some example usage:

>>> from collections import namedtuple
>>> class CAnswer(namedtuple("CAnswer","x fixed")):
...             def __bool__(self):
...                     return self.fixed is True
...             __nonzero__ = __bool__  # For Python 2. Called by bool in Py2.
...             def __repr__(self):
...                     return "<CA: {}>".format(self.x)
...
>>> val = [3, 2, 0, 1, 5, 9, 4]
>>> fix = [2, 5]
>>> lst = [ CAnswer(v, i in fix) for i, v in enumerate(val)]

>>> print("Start   ", 0, ": ", lst)
Start    0 :  [<CA: 3>, <CA: 2>, <CA: 0>, <CA: 1>, <CA: 5>, <CA: 9>, <CA: 4>]

Using a predicate to filter.

>>> for i in range(4):  # doctest: +NORMALIZE_WHITESPACE
...     shuffle_subset(lst, lambda x : x.fixed)
...     print([lst[i] for i in fix], end=" ")
...
[<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>]

>>> for i in range(4):                # doctest: +NORMALIZE_WHITESPACE
...     shuffle_subset(lst)           # predicate = bool()
...     print([lst[i] for i in fix], end=" ")
...
[<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>]

"""
from __future__ import print_function
import random


def shuffle_subset(lst, predicate=None):
    """All elements in lst, except a sub-set, are shuffled.

    The predicate defines the sub-set of elements in lst that should
    not be shuffled:

      + The predicate is a callable that returns True for fixed
      elements, predicate(element) --> True or False.

      + If the predicate is None extract those elements where
      bool(element) == True.

    """
    predicate = bool if predicate is None else predicate
    fixed_subset = [(i, e) for i, e in enumerate(lst) if predicate(e)]

    fixed_subset.reverse()      # Delete fixed elements from high index to low.
    for i, _ in fixed_subset:
        del lst[i]

    random.shuffle(lst)

    fixed_subset.reverse()      # Insert fixed elements from low index to high.
    for i, e in fixed_subset:
        lst.insert(i, e)

if __name__ == "__main__":
    import doctest
    doctest.testmod()
#/usr/bin/env python
“”“无序排列列表中的元素,但元素的子集除外。”。
子集合是那些应在中保持其位置的元素
列表。一些示例用法:
>>>从集合导入namedtuple
>>>类CAnswer(名为tuple(“CAnswer”,“x fixed”):
…定义布尔(自我):
…返回self.fixed是真的
对于Python2。
…定义报告(自我):
…返回“”。格式(self.x)
...
>>>val=[3,2,0,1,5,9,4]
>>>fix=[2,5]
>>>lst=[CAnswer(v,i在fix中)表示枚举中的i,v(val)]
>>>打印(“开始”,0,:”,lst)
开始0:[,,]
使用谓词进行筛选。
>>>对于范围(4)中的i:#doctest:+规范化_空格
…洗牌_子集(lst,lambda x:x.fixed)
…打印([lst[i]表示修复中的i],end=“”)
...
[, ] [, ] [, ] [, ]
>>>对于范围(4)中的i:#doctest:+规范化_空格
…洗牌_子集(lst)#谓词=bool()
…打印([lst[i]表示修复中的i],end=“”)
...
[, ] [, ] [, ] [, ]
"""
来自未来导入打印功能
随机输入
def shuffle_子集(lst,谓词=None):
“”“lst中的所有元素(子集除外)都被洗牌。
谓词定义了lst中应该
不要被洗牌:
+谓词是一个可调用的,它为固定值返回True
元素,谓词(元素)-->True或False。
+如果谓词为None,则提取以下元素:
布尔(元素)=真。
"""
predicate=bool,如果谓词是None-else谓词
fixed_subset=[(i,e)表示枚举(lst)中的i,e如果谓词(e)]
fixed_subset.reverse()#从高索引到低索引删除固定元素。
对于i,在固定子集中:
del lst[i]
随机。洗牌(lst)
fixed_subset.reverse()#插入从低索引到高索引的固定元素。
对于固定_子集中的i,e:
一、插入(即,e)
如果名称=“\uuuuu main\uuuuuuuu”:
进口医生测试
doctest.testmod()

我尝试了两种方法——首先只使用random.shuffle(),然后将某些元素恢复到原始位置。另一种方法是使用random.choice对要随机化的元素进行选择,或者选择某些元素作为“冻结”元素。然而,这两种方法似乎都有点不合法,而且绝对不是python式的。看起来很好,应该可以工作,但作为一个noob,我需要几秒钟来理解这一点。非常感谢!代码不错。洗牌未冻结的索引,其他什么都不做。这是我做的,但不太像蟒蛇的方式-没有列表理解,也没有在两个元素上同时拖动,所以谢谢!在我的脚本中实现了这一点,并且非常完美,同时非常python和优雅。再次非常感谢!StackOverflow的成员统治世界;)@Pawel:如果列表中有重复项,此解决方案可能会中断。另外(不太重要的)items.index()可以扫描整个列表中的单个值。这使得算法在时间上是二次的。@J.F.塞巴斯蒂安你是对的,谢谢你指出这一点!然而,对于手头的问题(对测验问题的答案进行洗牌),两者都不应该构成问题。它们不是对测验问题的理所当然的答案,而是类似的东西——调查系统中的答案。列表中没有重复项,其长度很少会超过10项,也几乎不会超过30项,因此我发现这种方式非常适合我的需要——它清晰、简单,而且,对我来说可能最重要的是——易于理解。我是一个python新手(不是程序员,甚至不是IT人员),所以我需要一些代码来理解和学习。