Hướng dẫn python find repeating pattern in list - python tìm mẫu lặp lại trong danh sách

Tôi có một danh sách các danh sách và mỗi danh sách có một chuỗi lặp lại. Tôi đang cố gắng đếm độ dài của chuỗi số nguyên lặp đi lặp lại trong danh sách:

list_a = [111,0,3,1,111,0,3,1,111,0,3,1] 

list_b = [67,4,67,4,67,4,67,4,2,9,0]

list_c = [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,23,18,10]

Cái nào sẽ trở lại:

list_a count = 4 (for [111,0,3,1])

list_b count = 2 (for [67,4])

list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])

Bất kỳ lời khuyên hoặc lời khuyên sẽ được hoan nghênh. Tôi đang cố gắng giải quyết nó với re.compile ngay bây giờ nhưng, nó không hoàn toàn đúng.

Chất nền viên đầu tiên (và ngắn nhất) sẽ luôn luôn lặp lại nhiều nhất, nếu nó phù hợp với các tiêu chí khác

#!/usr/bin/env Python
Defcycle (danh sách): cycle(list):
# Danh sách lưu trữ các chu kỳ ngắn nhất
ngắn nhất = [] = []
# Trả về danh sách số nguyên đơn và không lặp lại
iflen (danh sách) len(list) <= 1: return list
iflen (set (danh sách)) == LEN (danh sách): returnList len(set(list)) == len(list): return list
# Loop thông qua danh sách mở rộng và so sánh
# Nhóm các yếu tố cho đến khi thấy một chuỗi
FREXINRANGE (LEN (DANH SÁCH)): x in range(len(list)):
iflist [0: x] == Danh sách [x: 2*x]: list[0:x] == list[x:2*x]:
ngắn nhất = danh sách [0: x] = list[0:x]
returnShortest shortest
Đầu tiên = [1,1,1] = [1,1,1]
Thứ hai = [1,2,1,2,1,2] = [1,2,1,2,1,2]
Thứ ba = [1,2,1,2,1] = [1,2,1,2,1]
Thứ tư = [1,1,3,1,1,3] = [1,1,3,1,1,3]
Thứ năm = [5] = [5]
Thứ sáu = [] = []
Thứ bảy = [1,2,3,4] = [1,2,3,4]
Eighth = [7,7,7] = [7,7,7]
printcycle (đầu tiên) cycle(first)
printcycle (thứ hai) cycle(second)
printcycle (thứ ba) cycle(third)
printcycle (thứ tư) cycle(fourth)
printcycle (thứ năm) cycle(fifth)
printcycle (thứ sáu) cycle(sixth)
printcycle (thứ bảy) cycle(seventh)
printcycle (thứ tám) cycle(eighth)
'' '
$ Python chu kỳ.py
[1]
[1, 2]
[1, 2]
[1, 1, 3]
[5]
[]
[1, 2, 3, 4]
[7]
'' '

Tôi thấy rằng đã có một câu trả lời được chấp nhận, trước khi tôi có thể viết câu trả lời này. Đó là một chút nản lòng đối với tôi với tư cách là một người đánh giá, nhưng tôi đã viết một thay thế mã và có một số suy nghĩ liên quan đến mã của bạn.

Đánh giá mã

  • Tài liệu về mã của bạn - & nbsp; để đoán mã của bạn đang làm gì bằng cách đọc đơn giản là không dễ dàng lắm. Nó rất có thể có một vài ý kiến ​​về những gì nó cố gắng để đạt được.
  • Tên biến tốt hơn - & NBSP; Nói chung, hãy cố gắng sử dụng các tên biến mô tả nội dung. Những cái tên như x,
    list_a count = 4 (for [111,0,3,1])
    
    list_b count = 2 (for [67,4])
    
    list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
    
    0,
    list_a count = 4 (for [111,0,3,1])
    
    list_b count = 2 (for [67,4])
    
    list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
    
    1 (mà tôi sẽ đọc là biểu thức?), V.v., không có nhiều thông tin.
  • Regex thường đắt tiền - & nbsp; nói chung Regex, trong khi cũng là một người tuyệt vời, có phần bị lạm dụng quá mức. Xin lưu ý rằng cần có thời gian để xây dựng các mẫu và phù hợp với các mẫu, đặc biệt là so với các trận đấu chuỗi đơn giản.

Một số cấu trúc mới (?)

Tôi không chắc bạn đã biết những thứ này chưa, nhưng có một vài cấu trúc mới mà tôi muốn cho bạn thấy:

  • Chuỗi lặp lại - & nbsp; chuỗi có thể được nhân (AKA trùng lặp) bằng toán tử nhân.

    text = "abc"
    print text * 3     # Will output "abcabcabc"
    
  • list_a count = 4 (for [111,0,3,1])
    
    list_b count = 2 (for [67,4])
    
    list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
    
    2 với nhiều đầu ra - & nbsp; ________ 13 sẽ chia ____10 cho
    list_a count = 4 (for [111,0,3,1])
    
    list_b count = 2 (for [67,4])
    
    list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
    
    5 và trả về ước số và phần còn lại. Điều này có thể được lưu trữ trực tiếp thành một tuple như sau:

    div, rest = divmod(13, 5)   # Giving div == 2, rest = 3
    
  • Cắt lát và dây xúc xắc - Như Python 2.3, người ta có thể cắt dây. Các biến thể phổ biến nhất cho biết bạn muốn có bao nhiêu ký tự từ START như
    list_a count = 4 (for [111,0,3,1])
    
    list_b count = 2 (for [67,4])
    
    list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
    
    6 hoặc nếu bạn muốn phần còn lại của văn bản như
    list_a count = 4 (for [111,0,3,1])
    
    list_b count = 2 (for [67,4])
    
    list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
    
    7. Điều này có thể rất hữu ích ...
  • Một biến số hơi fancier

    list_a count = 4 (for [111,0,3,1])
    
    list_b count = 2 (for [67,4])
    
    list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
    
    8 - sử dụng .format kết hợp với
    list_a count = 4 (for [111,0,3,1])
    
    list_b count = 2 (for [67,4])
    
    list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
    
    8 có thể tạo ra đầu ra đẹp hơn khá dễ dàng:

    print 'i: {}, sub: {}, div: {}, mod: {}'.format(i, source[:i], div, rest)
    

    Điều này sẽ xuất ra trên cùng một dòng, một cái gì đó như:

    i: 4, sub: abcd, div: 2, mod: 3
    
  • ________ 20 khối sau

    text = "abc"
    print text * 3     # Will output "abcabcabc"
    
    1 ?! -& nbsp; Điều này sẽ có ý nghĩa sau này, nhưng nếu vòng lặp
    text = "abc"
    print text * 3     # Will output "abcabcabc"
    
    1 hoàn thành bình thường, nó sẽ không nhập tùy chọn ________ 23 khối. Nói cách khác, nếu bạn
    text = "abc"
    print text * 3     # Will output "abcabcabc"
    
    4 ra khỏi một vòng lặp
    text = "abc"
    print text * 3     # Will output "abcabcabc"
    
    1 sẽ không vào khối
    text = "abc"
    print text * 3     # Will output "abcabcabc"
    
    0. Điều này có thể được sử dụng để xác minh rằng vòng lặp
    text = "abc"
    print text * 3     # Will output "abcabcabc"
    
    1 thực sự đã tìm thấy/làm một cái gì đó và cung cấp một giải pháp thay thế nếu không.

    for i in range(5):
        print i
       if i == 3:
          break
    else:
       print "Nothing larger than 3..."
    

Mã thay thế

Tôi đã không nhận xét quá nhiều về thuật toán bạn đã chọn, vì tôi thấy nó hơi khó hiểu, vì vậy tôi nghĩ những gì anh ấy đang cố gắng đạt được và phương pháp thay thế là gì. Sau đó tôi đã đưa ra những yêu cầu này cho mã:

  • Bạn đang tìm kiếm bộ con lặp lại tối đa hoàn toàn điền vào chuỗi ban đầu. Điều này có nghĩa là:
    • Chiều dài phần phụ của ứng cử viên, sau đó phải chia độ dài chuỗi ban đầu mà không có bất kỳ ký tự còn lại (hoặc ký tự nghỉ nữa)
    • Chất nền ứng viên không thể vượt quá một nửa chiều dài của chuỗi ban đầu, vì nó không thể được nhân đôi
    • Chất nền viên đầu tiên (và ngắn nhất) sẽ luôn luôn lặp lại nhiều nhất, nếu nó phù hợp với các tiêu chí khác

Vì vậy, một cách để viết ra điều này là như thế này:

def repeatedSubstring(source):
  """Look for the shortest substring which when repeated equals
     the source string, without any left over characters.
  """
  length = len(source)
  print '\nOriginal text: {}. Length: {}'.format(source, length)

  # Check candidate strings
  for i in range(1, length/2+1):
    repeat_count, leftovers = divmod(length, i)
    # print 'i: {}, sub: {}, div: {}, mod: {}'.format(i, source[:i], repeat_count, leftovers)
    # print 'repeated: {}'.format(source[:i]*repeat_count)

    # Check for no leftovers characters, and equality when repeated 
    if (leftovers == 0) and (source == source[:i]*repeat_count):
      print 'Found repeated substring: {}, count: {}'.format(source[:i], repeat_count)
      break
  else:
    print "Couldn't find any repeated substring"

repeatedSubstring("abcdeabcde")
repeatedSubstring("abcdeabcdef")
repeatedSubstring("aaaaa")

Tôi đã nhận xét một số câu lệnh

list_a count = 4 (for [111,0,3,1])

list_b count = 2 (for [67,4])

list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
8 và để lại nó một chút dài hơn một chút so với mã gốc.

Nếu bạn muốn, bạn có thể dễ dàng thay thế các câu lệnh

list_a count = 4 (for [111,0,3,1])

list_b count = 2 (for [67,4])

list_c count = 10 (for [1,2,3,4,5,6,7,8,9,0])
8 còn lại bằng
div, rest = divmod(13, 5)   # Giving div == 2, rest = 3
0 và
div, rest = divmod(13, 5)   # Giving div == 2, rest = 3
1. Một phiên bản bị tước xuống sau đó sẽ trông giống như:

def repeatedSubstringCount(source):
  """Look for the shortest substring which when repeated equals
     the source string, without any left over characters.
     Return the maximum repeat count, 1 if none found.
  """
  length = len(source)

  # Check candidate strings
  for i in range(1, length/2+1):
    repeat_count, leftovers = divmod(length, i)

    # Check for no leftovers characters, and equality when repeated 
    if (leftovers == 0) and (source == source[:i]*repeat_count):
      return repeat_count

  return 1

Tôi vẫn để lại một vài bình luận trong đó, để có thể có một số ý tưởng về những gì đang xảy ra. Tôi cũng đã thay đổi tên thành "REBEARDSUBSTRINGCOUNT" để chỉ ra cả hai chức năng làm, nhưng cũng là những gì nó trả về.