2010-10-13 28 views
5

Tôi có một thư mục của 9 hình ảnh:Làm thế nào để liệt kê một chuỗi hình ảnh một cách hiệu quả? Numercial so sánh chuỗi bằng Python

 
image_0001, image_0002, image_0003 
image_0010, image_0011 
image_0011-1, image_0011-2, image_0011-3 
image_9999 

Tôi muốn để có thể liệt kê chúng trong một cách hiệu quả, như thế này (4 mục cho 9 hình ảnh):

 
(image_000[1-3], image_00[10-11], image_0011-[1-3], image_9999) 

Có cách nào trong python, trả về một thư mục hình ảnh, theo cách ngắn/rõ ràng (không liệt kê mọi tệp) không?

Vì vậy, có thể là một cái gì đó như thế này:

danh sách tất cả hình ảnh, sắp xếp số lượng, tạo ra một danh sách (tính mỗi hình ảnh theo thứ tự từ đầu). Khi thiếu hình ảnh (tạo danh sách mới), tiếp tục cho đến khi danh sách tệp gốc hoàn tất. Bây giờ tôi chỉ nên có một số danh sách có chứa các chuỗi không bị hỏng.

Tôi đang cố gắng để dễ đọc/mô tả danh sách các số. Nếu tôi có một chuỗi 1000 tệp liên tiếp Có thể liệt kê rõ ràng là tệp [0001-1000] thay vì tệp ['0001', '0002', '0003' vv ...]

Edit1 (based về đề nghị): Với một danh sách phẳng, làm thế nào bạn sẽ lấy được các mẫu glob?

Edit2 Tôi đang cố gắng giải quyết vấn đề thành từng phần nhỏ hơn. Dưới đây là một ví dụ về một phần của giải pháp: công trình data1, data2 lợi nhuận 0010 là 64, data3 (các dữ liệu RealWorld) không hoạt động:

# Find runs of consecutive numbers using groupby. The key to the solution 
# is differencing with a range so that consecutive numbers all appear in 
# same group. 
from operator import itemgetter 
from itertools import * 

data1=[01,02,03,10,11,100,9999] 
data2=[0001,0002,0003,0010,0011,0100,9999] 
data3=['image_0001','image_0002','image_0003','image_0010','image_0011','image_0011-2','image_0011-3','image_0100','image_9999'] 

list1 = [] 
for k, g in groupby(enumerate(data1), lambda (i,x):i-x): 
    list1.append(map(itemgetter(1), g)) 
print 'data1' 
print list1 

list2 = [] 
for k, g in groupby(enumerate(data2), lambda (i,x):i-x): 
    list2.append(map(itemgetter(1), g)) 
print '\ndata2' 
print list2 

lợi nhuận:

data1 
[[1, 2, 3], [10, 11], [100], [9999]] 

data2 
[[1, 2, 3], [8, 9], [64], [9999]] 
+0

Tại sao 'image_00 [10-11] 'và không' image_001 [0-1] '? – eumiro

+0

image_00 [10-11] hoặc image_001 [0-1], vâng tôi đoán đó là một ký tự ít hơn – user178686

+0

Cynically: vâng, có một cách. Tôi nghi ngờ (nhưng có thể sai) rằng có một số chức năng thư viện để làm điều này. Viết một số mã, hỏi một cái gì đó cụ thể hơn (ví dụ như làm thế nào tôi có thể so sánh các chuỗi tương tự) sau khi bạn đã làm 'os.listdir (đường dẫn)', v.v. –

Trả lời

6

Đây là một thực hiện những gì bạn muốn làm việc để đạt được, bằng cách sử dụng mã bạn thêm vào như là một điểm khởi đầu:

#!/usr/bin/env python 

import itertools 
import re 

# This algorithm only works if DATA is sorted. 
DATA = ["image_0001", "image_0002", "image_0003", 
     "image_0010", "image_0011", 
     "image_0011-1", "image_0011-2", "image_0011-3", 
     "image_0100", "image_9999"] 

def extract_number(name): 
    # Match the last number in the name and return it as a string, 
    # including leading zeroes (that's important for formatting below). 
    return re.findall(r"\d+$", name)[0] 

def collapse_group(group): 
    if len(group) == 1: 
     return group[0][1] # Unique names collapse to themselves. 
    first = extract_number(group[0][1]) # Fetch range 
    last = extract_number(group[-1][1]) # of this group. 
    # Cheap way to compute the string length of the upper bound, 
    # discarding leading zeroes. 
    length = len(str(int(last))) 
    # Now we have the length of the variable part of the names, 
    # the rest is only formatting. 
    return "%s[%s-%s]" % (group[0][1][:-length], 
     first[-length:], last[-length:]) 

groups = [collapse_group(tuple(group)) \ 
    for key, group in itertools.groupby(enumerate(DATA), 
     lambda(index, name): index - int(extract_number(name)))] 

print groups 

này in ['image_000[1-3]', 'image_00[10-11]', 'image_0011-[1-3]', 'image_0100', 'image_9999'], đó là những gì bạn muốn.

LỊCH SỬ: Tôi ban đầu trả lời câu hỏi ngược, như @Mark Ransom đã chỉ ra bên dưới. Vì lợi ích của lịch sử, câu trả lời ban đầu của tôi là:

Bạn đang tìm kiếm glob. Hãy thử:

import glob 
images = glob.glob("image_[0-9]*") 

Hoặc, sử dụng ví dụ của bạn:

images = [glob.glob(pattern) for pattern in ("image_000[1-3]*", 
    "image_00[10-11]*", "image_0011-[1-3]*", "image_9999*")] 
images = [image for seq in images for image in seq] # flatten the list 
+0

Tôi nghĩ rằng giải pháp này là ngược lại từ những gì câu hỏi được hỏi. Với một danh sách phẳng, làm thế nào bạn sẽ lấy được các mô hình glob? –

+0

@Mark, bạn nói đúng, tôi hiểu lầm câu hỏi (và tiêu đề của nó thực sự nên là "Với một danh sách phẳng, làm thế nào bạn sẽ lấy được các mẫu glob?"). Tôi nghĩ tôi sẽ ngủ một chút trước khi thử lại lần nữa:] –

+0

@ Frédéric @Mark. Cảm ơn cả hai vì sự giúp đỡ của bạn. Tôi thực sự thích vấn đề này. Tôi đang học khi tôi đi. – user178686

2
def ranges(sorted_list): 
    first = None 
    for x in sorted_list: 
     if first is None: 
      first = last = x 
     elif x == increment(last): 
      last = x 
     else: 
      yield first, last 
      first = last = x 
    if first is not None: 
     yield first, last 

Chức năng increment là trái như một bài tập cho người đọc.

Chỉnh sửa: đây là ví dụ về cách nó sẽ được sử dụng với số nguyên thay vì chuỗi làm đầu vào.

def increment(x): return x+1 

list(ranges([1,2,3,4,6,7,8,10])) 
[(1, 4), (6, 8), (10, 10)] 

Đối với mỗi dải liền kề trong đầu vào, bạn nhận được cặp cho biết bắt đầu và kết thúc phạm vi.Nếu một phần tử không thuộc phạm vi, giá trị bắt đầu và kết thúc giống hệt nhau.

+0

cảm ơn tôi không thực sự hiểu. Vì vậy, giả sử tôi đã sắp xếp các tệp vào danh sách: sorted_list = ['image_0001', 'image_0002', 'image_0003', 'image_0010', 'image_0011'] ... bạn có thể giải thích những gì bạn đã hiển thị cho tôi hay không. Đối với mỗi mục trong danh sách được sắp xếp (nếu bạn tăng nó, hãy kiểm tra xem nó có tồn tại trong phần còn lại của danh sách) không ??? – user178686

+1

@user, thuật toán này sẽ kiểm tra từng phần tử để xem liệu nó có nên được đưa vào chuỗi hiện tại hay không bằng cách kiểm tra xem nó có bằng với + 1 hay không. Nếu có, thì trình tự hiện tại được mở rộng; nếu không thì trình tự được sinh ra dưới dạng bộ tuple và chuỗi hiện tại được đặt lại thành phần tử mới. Nếu chúng ta có thể đảm bảo rằng đầu vào không trống, điều này thậm chí có thể được đơn giản hóa. –

+0

Thankyou. Ok, vì vậy tôi hiểu rằng nó kiểm tra từng phần tử để xem liệu nó có bằng với phần tử trước đó + 1 hay không. Tôi không hiểu "nếu không trình tự được sinh ra như một bộ" ... – user178686

3

Được rồi, vì vậy tôi đã tìm thấy câu hỏi của bạn là một câu đố hấp dẫn. Tôi đã để lại cách "nén" phạm vi số cho bạn (được đánh dấu là TODO), vì có các cách khác nhau để thực hiện điều đó tùy thuộc vào cách bạn thích định dạng và nếu bạn muốn số lượng yếu tố tối thiểu hoặc chuỗi mô tả tối thiểu độ dài.

Giải pháp này sử dụng cụm từ thông dụng đơn giản (chuỗi số) để phân loại từng chuỗi thành hai nhóm: tĩnh và biến. Sau khi dữ liệu được phân loại, tôi sử dụng nhóm để thu thập dữ liệu tĩnh thành các nhóm phù hợp dài nhất để đạt được hiệu quả tóm tắt. Tôi trộn các chỉ số số nguyên sentinals vào kết quả (trong matchGrouper) vì vậy tôi có thể chọn lại các phần khác nhau từ tất cả các phần tử (trong giải nén).

import re 
import glob 
from itertools import groupby 
from operator import itemgetter 

def classifyGroups(iterable, reObj=re.compile('\d+')): 
    """Yields successive match lists, where each item in the list is either 
    static text content, or a list of matching values. 

    * `iterable` is a list of strings, such as glob('images/*') 
    * `reObj` is a compiled regular expression that describes the 
      variable section of the iterable you want to match and classify 
    """ 
    def classify(text, pos=0): 
     """Use a regular expression object to split the text into match and non-match sections""" 
     r = [] 
     for m in reObj.finditer(text, pos): 
      m0 = m.start() 
      r.append((False, text[pos:m0])) 
      pos = m.end() 
      r.append((True, text[m0:pos])) 
     r.append((False, text[pos:])) 
     return r 

    def matchGrouper(each): 
     """Returns index of matches or origional text for non-matches""" 
     return [(i if t else v) for i,(t,v) in enumerate(each)] 

    def unpack(k,matches): 
     """If the key is an integer, unpack the value array from matches""" 
     if isinstance(k, int): 
      k = [m[k][1] for m in matches] 
     return k 

    # classify each item into matches 
    matchLists = (classify(t) for t in iterable) 

    # group the matches by their static content 
    for key, matches in groupby(matchLists, matchGrouper): 
     matches = list(matches) 
     # Yield a list of content matches. Each entry is either text 
     # from static content, or a list of matches 
     yield [unpack(k, matches) for k in key] 

Cuối cùng, chúng tôi thêm đủ logic để thực hiện in ấn khá đầu ra và chạy ví dụ.

def makeResultPretty(res): 
    """Formats data somewhat like the question""" 
    r = [] 
    for e in res: 
     if isinstance(e, list): 
      # TODO: collapse and simplify ranges as desired here 
      if len(set(e))<=1: 
       # it's a list of the same element 
       e = e[0] 
      else: 
       # prettify the list 
       e = '['+' '.join(e)+']' 
     r.append(e) 
    return ''.join(r) 

fnList = sorted(glob.glob('images/*')) 
re_digits = re.compile(r'\d+') 
for res in classifyGroups(fnList, re_digits): 
    print makeResultPretty(res) 

Thư mục hình ảnh của tôi được tạo từ ví dụ của bạn. Bạn có thể thay fnList với danh sách sau đây để kiểm tra:

fnList = [ 
'images/image_0001.jpg', 
'images/image_0002.jpg', 
'images/image_0003.jpg', 
'images/image_0010.jpg', 
'images/image_0011-1.jpg', 
'images/image_0011-2.jpg', 
'images/image_0011-3.jpg', 
'images/image_0011.jpg', 
'images/image_9999.jpg'] 

Và khi tôi chạy chống lại thư mục này, sản lượng của tôi trông giống như:

StackOverflow/3926936% python classify.py 
images/image_[0001 0002 0003 0010].jpg 
images/image_0011-[1 2 3].jpg 
images/image_[0011 9999].jpg 
+0

Cảm ơn, tôi rất không chắc chắn về những gì bạn đang làm. Bạn có thể thêm một số nhận xét giúp tôi liên quan đến ví dụ image_0002, image_0003 v.v. Nếu bạn có thể thêm danh sách thử nghiệm, tôi có thể duyệt qua và chạy từng bit một. – user178686

+0

THANKYOU cho thời gian của bạn Shane. Tôi sẽ tiếp tục xem xét giải pháp itertools của bạn; Tôi nghĩ tôi có thể học được rất nhiều từ nó. Edit2 trong bài đăng gốc, là kết quả của việc googling/nghiên cứu giải pháp nhận xét tốt của bạn. – user178686

Các vấn đề liên quan