【问题标题】:Subtract and add two lists without changing their order in Python减去和添加两个列表而不改变它们在 Python 中的顺序
【发布时间】:2011-07-31 13:26:20
【问题描述】:

如果我有列表[68,31,93,35,10](所有数字都会不同)和列表[93,0,22,10,99,33,21,9](同样,所有数字都会不同,但可能与另一个列表重叠),我需要能够得到正好[68,31,93,35,10,0,22,99,33,21,9],其中第二个列表被附加到第一个列表中,没有重复。我还需要能够准确地获得[68,31,35],其中第一个列表删除了第二个列表中的所有重复项。输出的顺序应始终与输入的顺序相同。我该怎么做? (如果简单的话,一个班轮会很好。)

【问题讨论】:

    标签: python list addition subtraction


    【解决方案1】:
    l1 = [68, 31, 93, 35,10]
    l2 = [93, 0, 22, 10, 99, 33, 21,9]
    
    l1 + [x for x in l2 if not x in l1]
    # [68, 31, 93, 35, 10, 0, 22, 99, 33, 21, 9]
    
    [x for x in l1 if not x in l2]
    # [68, 31, 35]
    

    编辑:对于长列表,您不想进行所有这些列表查找。以下是另外两个食谱:

    联合:

    from collections import OrderedDict
    OrderedDict().fromkeys(l1+l2).keys()
    # [68, 31, 93, 35, 10, 0, 22, 99, 33, 21, 9]
    

    区别:

    s = set(l2)
    [x for x in l1 if not x in s]
    # [68, 31, 35]
    

    【讨论】:

      【解决方案2】:

      假设输入 l1l2,您可以计算它们的有序联合:

      l1 + filter(lambda x: x not in l1, l2)
      

      要得到有序差 l1 - l2,写

      filter(lambda x: x not in l2, l1)
      

      或者,使用列表推导:

      >>> l1 = [68,31,93,35,10]
      >>> l2 = [93,0,22,10,99,33,21,9]
      >>> l1 + [el2 for el2 in l2 if el2 not in l1]
      [68, 31, 93, 35, 10, 0, 22, 99, 33, 21, 9]
      >>> [el1 for el1 in l1 if el1 not in l2]
      [68, 31, 35]
      

      如果您使用非常大的列表(性能是一个问题)执行此操作,请构造一个 set 以加快查找速度:

      >>> sl1 = set(s1)
      >>> l1 + [el2 for el2 in l2 if el2 not in sl1]
      [68, 31, 93, 35, 10, 0, 22, 99, 33, 21, 9]
      >>> sl2 = set(s2)
      >>> [el1 for el1 in l1 if el1 not in sl2]
      [68, 31, 35]
      

      【讨论】:

      • 过滤器和列表理解的速度会有很大差异吗?
      • @D K 这完全取决于 Python 实现。我假设列表推导往往更快,但这只是一个猜测。使用 JITing Python 解释器,这两种变体几乎可以肯定是完全相等的。
      • @D K 我忘了一件事:如果列表非常大,您应该构造一个set 以便更快地查找。更新了答案。
      • @D K 嗯?仔细看,这些集合仅用于成员资格测试,顺序无关紧要。
      • 哦,我明白了。感谢您的所有帮助!
      【解决方案3】:
      def unique_chain(*iters):
          seen = set()
          for it in iters:
              for item in it:
                  if item not in seen:
                      yield item
                      seen.add(item)
      
      print list(unique_chain([68, 31, 93, 35,10], [93, 0, 22, 10, 99, 33, 21,9]))
      

      【讨论】:

        【解决方案4】:
        >>> a = [68,31,93,35,10]
        >>> b = [93,0,22,10,99,33,21,9]
        >>> result= []
        >>> temp = a + b
        >>> [result.append(x) for x in temp if x not in result]
        >>> result
            [68, 31, 93, 35, 10, 0, 22, 99, 33, 21, 9]
        >>> a = set(a)
        >>> b = set(b)
        >>> a - b
            set([35, 68, 31])
        

        【讨论】:

          【解决方案5】:

          也许你可以使用OrderedSet

          import collections
          
          class OrderedSet(collections.MutableSet):
              def __init__(self, iterable, *args, **kwargs):
                  super(OrderedSet, self).__init__(*args, **kwargs)
                  self._data = collections.OrderedDict()
                  self.update(iterable)
          
              def update(self, iterable):
                  self._data.update((x, None) for x in iterable)
          
              def __iter__(self):
                  return iter(self._data)
          
              def __contains__(self, value):
                  return value in self._data
          
              def __len__(self):
                  return len(self._data)
          
              def __le__(self, other):
                  if isinstance(other, OrderedSet):
                      return self._data <= other._data
                  return super(OrderedSet, self).__le__(other)
          
              def __and__(self, other):
                  # Overrided by make the order of self the preferred one
                  if isinstance(other, collections.Set):
                      return self._from_iterable(value for value in self 
                                                       if value in other)
                  return self & set(other)
          
              def __ior__(self, other):
                  self.update(other)
                  return self
          
              def add(self, value):
                  self._data[value] = None
          
              def discard(self, value):
                  self._data.pop(value, None)
          
              def __repr__(self):
                  return "%s(%r)" % (type(self).__name__, self._data.keys())
          

          【讨论】:

            【解决方案6】:

            这样定义前两个列表后,

            a = [68,31,93,35,10]
            b = [93,0,22,10,99,33,21,9]
            

            这是第一个问题的单线解决方案,

            c = [x for x in a+b if x not in set(a).intersection(set(b))]
            

            第二个问题的单线,

            d = [x for x in a+b if x not in b]
            

            【讨论】:

              猜你喜欢
              • 2020-07-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-09-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多