【问题标题】:Specific sequence stored in a list存储在列表中的特定序列
【发布时间】:2014-08-18 10:12:46
【问题描述】:

我正在寻找一种方法来有效地搜索具有特定值序列的列表。顺序很重要!例如:

[x,y,z] 和 [x,z,y] 包含相同的值,但它们的顺序不同

但是:

  • [x,y,z]、[y,z,x] 和 [z,x,y] 对我来说都是一样的。
  • [x,z,y]、[z,y,x] 和 [x,z,y] 也都一样。

我想运行一个查找连接部分的脚本。例如,如果我正在寻找 [x,y,z] 我会寻找

mylist1 = ['a','b','c']
mylist2 = ['b','a','c']
def is_sequence_same(thelist,somelist):
    if (thelist[0] == somelist[0] and thelist[1] == somelist[1]):
       return True
    if (thelist[1] == somelist[1] and thelist[2] == somelist[2]):
        return True
    if (thelist[0] == somelist[1] and thelist[1] == somelist[0]):
        return False
    if  (thelist[0] == somelist[2] and thelist[1] == somelist[2]):
        return False
    else:
        return None
is_sequence_same(mylist1,mylist2)

函数返回: 是的——如果顺序和我问的一样, False - 如果序列相反

我当前的功能不完整。但是,我认为应该有更优雅的方法来解决问题

【问题讨论】:

  • 假设您没有重复:在 mylist2 中查找 x=mylist1[0],如果不存在,则返回 False。从 mylist2 中删除 x 并将相同的逻辑递归应用于 mylist1[1:]

标签: python list python-3.x return


【解决方案1】:

这假设列表保证不为空且长度相同:

def is_sequence_same(first, second):
    try:
        i = second.index(first[0])
        if i == -1:
            return False
        for e in first[1:]:
            i += 1
            if i == len(second):
                i = 0
            if e != second[i]:
                return False
        return True
    except ValueError:
        return False

【讨论】:

    【解决方案2】:

    如果有效地是指亚线性(即:您不想逐个搜索每个元素),那么执行data normalization 是一种很好的技术。

    如果你的元素有顺序,就像你的例子,这特别容易:

    def normalize_sequence( seq ):
        return tuple(sorted( seq )) #tuple is needed because lists are unhashable
    

    使用这种技术,您可以轻松地使用字典或集合来执行快速查找:

    existing_elements= set( map( normalize_sequence, ([1,4,2],[4,5,7]) ) )
    print normalize_sequence( [1,2,4] ) in existing_elements
    

    这比对每个元素进行迭代和比较要快得多,尤其是对于较大的列表。

    【讨论】:

      【解决方案3】:

      由于您正在寻找特定的循环,您可以修改两个列表以从相同元素开始,然后比较它们。适用于任何列表大小。假设列表的元素是唯一的。

      def is_sequence_same(list_a, list_b):
          if list_a and list_a[0] in list_b:                 # List_a not empty and first element exists in list_b
              first = list_b.index(list_a[0])                # Locate first element of list_a in list_b
          else:
              return False
          return list_a == (list_b[first:] + list_b[:first]) # Slice and compare
      

      例如:

      a = [1, 2, 3]
      b = [3, 1, 2]
      c = [2, 1, 3]
      
      > is_sequence_same(a, b)
      > True
      
      > is_sequence_same(b, c)
      > False
      > 
      > is_sequence_same(a, c)
      > False
      

      【讨论】:

        【解决方案4】:

        如果列表很长,这可能会很慢,但它本质上是在遍历列表所代表的序列的各种可能“起点”时进行列表比较。我假设每个字符可能不止一个,所以你不能直接进入 mylist[0]

        的第一场比赛
        mylist = ['a','b','c']
        wontmatch = ['b','a','c']
        willmatch = ['c','a','b']
        
        def sequence_equal(list1,list2):
            for r in range(0,len(list1)):
                if list1 == list2:
                    return True
                # Take the entry from the last index, and put it at the front, 
                # 'rotating' the list by 1
                list1.insert(0,list1.pop())
            return False
        
        print sequence_equal(mylist,willmatch)
        print sequence_equal(mylist,wontmatch)
        

        (编辑:这会根据 Magnus 的回答手动重新创建双端队列。)

        【讨论】:

          【解决方案5】:

          使用双端队列:

          from collections import deque
          
          def is_sequence_same(l1, l2):
              if l1 == l2:
                  return True
              if set(l1) != set(l2) or len(l1) != len(l2):
                  return False
              d2 = deque(l2)
              for i in range(len(l2)):
                  if l1 == list(d2):
                      return True
                  d2.rotate()
              return False
          

          【讨论】:

            猜你喜欢
            • 2021-12-14
            • 2023-01-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-07-18
            • 2017-12-27
            相关资源
            最近更新 更多