I have a directory of 9 images:
image_0001, image_0002, image_0003 image_0010, image_0011 image_0011-1, image_0011-2, image_0011-3 image_9999
I would like to be able to list them in an efficient way, like this (4 entries for 9 images):
(image_000[1-3], image_00[10-11], image_0011-[1-3], image_9999)
Is there a way in python, to return a directory of images, in a short/clear way (without listing every file)?
So, possibly something like this:
list all images, sort numerically, create a list (counting each image in sequence from start). When an image is missing (create a new list), continue until original file list is finished. Now I should just have some lists that contain non broken sequences.
I'm trying to make it easy to read/describe a list of numbers. If I had a sequence of 1000 consecutive files It could be clearly listed as file[0001-1000] rather than file['0001','0002','0003' etc...]
Edit1(based on suggestion): Given a flattened list, how would you derive the glob patterns?
Edit2 I'm trying to break the problem down into smaller pieces. Here is an example of part of the solution: data1 works, data2 returns 0010 as 64, data3 (the realworld data) doesn't work:
# 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
returns:
data1
[[1, 2, 3], [10, 11], [100], [9999]]
data2
[[1, 2, 3], [8, 9], [64], [9999]]
Here is a working implementation of what you want to achieve, using the code you added as a starting point:
This prints
['image_000[1-3]', 'image_00[10-11]', 'image_0011-[1-3]', 'image_0100', 'image_9999']
, which is what you want.HISTORY: I initially answered the question backwards, as @Mark Ransom pointed out below. For the sake of history, my original answer was:
You're looking for glob. Try:
Or, using your example:
The
increment
function is left as an exercise for the reader.Edit: here's an example of how it would be used with integers instead of strings as input.
For each contiguous range in the input you get a pair indicating the start and end of the range. If an element isn't part of a range, the start and end values are identical.
Okay, so I found your question to be a fascinating puzzle. I've left how to "compress" the numeric ranges up to you (marked as a TODO), as there are different ways to accomplish that depending on how you like it formatted and if you want the minimum number of elements or the minimum string description length.
This solution uses a simple regular expression (digit strings) to classify each string into two groups: static and variable. After the data is classified, I use groupby to collect the static data into longest matching groups to achieve the summary effect. I mix integer index sentinals into the result (in matchGrouper) so I can re-select the varying parts from all elements (in unpack).
Finally, we add enough logic to perform pretty printing of the output, and run an example.
My directory of images was created from your example. You can replace fnList with the following list for testing:
And when I run against this directory, my output looks like: