I need some help on sorting 2 lists..one with file listings and one with directory listings.
These lists are generated through another part in a much larger script that I cannot put on here.
filelist = ['EN088_EFH_030_comp_v011.mov', 'EN086_EHA_010_comp_v031.mov', 'EN083_WDA_400_comp_v021.mov', 'EN086_EHA_020_comp_v010.mov', 'EN083_WDA_450_comp_v012.mov']
folderlist = ['[EN086_EHA_010_comp_v031]', '[EN083_WDA_400_comp_v021]', '[EN086_EHA_020_comp_v010]', '[EN083_WDA_450_comp_v012]']
using .sort I can get the data to output like this.
[CB083_WDA_400_comp_v021]
[CB083_WDA_450_comp_v012]
[CB086_EHA_010_comp_v031]
[CB086_EHA_020_comp_v010]
CB083_WDA_400_comp_v021.mov
CB083_WDA_450_comp_v012.mov
CB086_EHA_010_comp_v031.mov
CB086_EHA_020_comp_v010.mov
CB088_EFH_030_comp_v011.mov
But I need it to output like this
[CB083_WDA_400_comp_v021]
CB083_WDA_400_comp_v021.mov
[CB083_WDA_450_comp_v012]
CB083_WDA_450_comp_v012.mov
[CB086_EHA_010_comp_v031]
CB086_EHA_010_comp_v031.mov
[CB086_EHA_020_comp_v010]
CB086_EHA_020_comp_v010.mov
CB088_EFH_030_comp_v011.mov
How can I go about sorting it but ignoring the [] during the sort?
Or what would I do to get the second output?
I'm kind of stumped on what I should do.
Any tips or suggestions?
....sort(key=lambda x: x.strip('[]'))
Related
Someone has challenged me to create a program that sorts their pictures into folders based on the month they were taken, and I want to do it in one line (I know, it's inefficient and unreadable, but I still want to do it because one-liners are cool)
I needed a for loop to accomplish this, but the only way I know of to use a for loop in one line is list comprehension, so that's what I did, but it creates an empty list, and doesn't print anything from the list or anything.
What I'm doing is renaming the file to be the month created + original filename (ex: bacon.jpg --> May\bacon.jpg)
Here is my code (Python 3.7.3):
import time
import os.path
[os.rename(str(os.fspath(f)), str(time.ctime(os.path.getctime(str(os.fspath(f))))).split()[1] + '\\' + str(os.fspath(f))) for f in os.listdir() if f.endswith('.jpg')]
and the more readable, non-list-comprehension version:
import time
import os.path
for f in os.listdir():
fn = str(os.fspath(f))
dateCreated = str(time.ctime(os.path.getctime(fn)))
monthCreated = dateCreated.split()[1]
os.rename(fn, monthCreated + '\\' + fn)
Is list comprehension a bad way to do it? Also, is there a reason why, if I print the list it's [] instead of [None, None, None, None, None, (continuing "None"s for every image moved)]?
Please note: I understand that it's inefficient and bad practice. If I were doing this for purposes other than just for fun to see if I could do it, I would obviously not try to do it in one line.
This is bad in two immediate respects:
You're using a list comprehension when you're not actually interested in constructing a list -- you ignore the object you just constructed.
Your construction has an ugly side effect in the OS.
Your purpose appears to be renaming a sequence of files, not constructing a list. The Python facility you want is, I believe, the map function. Write a function to change one file name, and then use map on a list of file names -- or tuples of old, new file names -- to run through the sequence of desired changes.
Is list comprehension a bad way to do it?
YES. But if you want to do it in one line, it is either that or using ";". For instance:
for x in range(5): print(x);print(x+2)
And, by the way, just renaming a file including a slash will not create a folder. You have to use os.mkdir('foldername').
In the end, if you really want to do that, I would just recommend doing it normally in many lines and then separating it with semicolons in a single line.
I have a list that should contain all my other lists. Currently I append every list separately but that just looks pretty ugly..
looplist = [] # initiate an empty list that contains all date from the other lists
[...]
looplist.append(internallist1)
[...]
looplist.append(internallist10)
the internallists are all getting initialized and filled in a for loop
You can simply use + to merge them.
You may check for more info.
If you want to have list of lists, check this topic.
listOne.extend(anotherList)
this could help you: https://docs.python.org/3/tutorial/datastructures.html
you can also do listOne+=anotherList and this is less expensive, as it doesn`t involve a function call like extend
To answer what you are asking, Just initialize looplist with your 10 lists.
looplist = [internallist1,
internallist2,
internallist3] #Note: internallist3,] is also valid, python allows trailing comma. Nifty!
However, your 10 lists really shouldn't be separately named lists in the first place if this is your real use case. Just use looplist[0] through looplist[9] instead from the get go.
The zip method could work for you as you stated your output should:
look something like [ [list1], [list2], ... , [list n] ]
in your case the code would be similar to
looplist = list(zip(internallist1,[...], internallist10))
Here is the block to analyse:
('images\\Principales\\Screenshot_1.png', '{"categories":[{"name":"abstract_","score":0.00390625},{"name":"outdoor_","score":0.01171875},{"name":"outdoor_road","score":0.41796875}],"description":{"tags":["road","building","outdoor","scene","street","city","sitting","empty","light","view","driving","red","sign","intersection","green","large","riding","traffic","white","tall","blue","fire"],"captions":[{"text":"a view of a city street","confidence":0.83864323826716347}]},"requestId":"73fc14d5-653f-4a0a-a45a-e7a425580361","metadata":{"width":150,"height":153,"format":"Png"},"color":{"dominantColorForeground":"Grey","dominantColorBackground":"Grey","dominantColors":["Grey"],"accentColor":"274A68","isBWImg":false}}')
I need to extract all elements after "description", but i don't know how to do that... (in fact, i need this elements:
"road", "building","outdoor","scene","street","city","sitting","empty","light","view","driving","red","sign","intersection","green","large","riding","traffic","white","tall","blue","fire"
I've been looking for several minutes already, but I do not understand how to do it! I'm a little beginner in learning "lists" element, and I still have a hard time understanding.
The "For" loop returns only 'images\\Principales\\Screenshot_1.png', then the big blocks left ...
Did you have a solution?
Thanks in advence!
EDIT:
Indeed, it is actually JSON! Thanks to the people who helped me :)
To extract the desired elements contained in the second block, I simply proceeded thus:
import json
ElementSeparate= '{"categories":[{"name":"abstract_","score":0.00390625},{"name":"outdoor_","score":0.01171875},{"name":"outdoor_road","score":0.41796875}],"description":{"tags":["road","building","outdoor","scene","street","city","sitting","empty","light","view","driving","red","sign","intersection","green","large","riding","traffic","white","tall","blue","fire"],"captions":[{"text":"a view of a city street","confidence":0.83864323826716347}]},"requestId":"73fc14d5-653f-4a0a-a45a-e7a425580361","metadata":{"width":150,"height":153,"format":"Png"},"color":{"dominantColorForeground":"Grey","dominantColorBackground":"Grey","dominantColors":["Grey"],"accentColor":"274A68","isBWImg":false}'
ElementSeparate = json.loads(ElementSeparate)
for a in ElementSeparate['description']['tags']:
print a
To me it looks like you're trying to parse JSON. You should use the JSON parser for the second element of the array. You'll get back either list or dictionary. Then you'll be able to extract data from "description" key has.
https://docs.python.org/3/library/json.html
I have many folders that contains several versionned files. Here are example files:
Cat_Setup_v01.mb
Cat_Setup_v18.mb
The version number has a two characters padding. This way, I can easily sort files using:
listFiles = glob.glob( myPath + "*.m*") # Retrieve files in my folder
listFiles.sort()
Unfortunately, I have some files with more than a hundred versions. Thus, my sorting method is broken with v1XX as they are sorted between v09 and v10.
Is there an efficient way I can sort my files in the right way without having to rename them all and change their padding?
sorted(versionNumber, key=int) combined with some split string operations could be an interesting trail but I'm affraid it will be too cumbersome.
I don't know Python much and as it seems to be an interesting language with a lot of possibilities, I'm pretty sure there is a more efficient way.
Cheers
Regular Expression may help you.
import re
file=["Cat_Setup_v91.mb", "Cat_Setup_v01.mb", "Cat_Setup_v119.mb"]
print sorted(file, key=lambda x: int(re.findall("(?<=v)\d+", x)[0]))
give the output:
['Cat_Setup_v01.mb', 'Cat_Setup_v91.mb', 'Cat_Setup_v119.mb']
Updated: change "(?<=v)\w*" to "(?<=v)\d+" according to #Rawing comment
So lets say I'm using Python's ftplib to retrieve a list of log files from an FTP server. How would I parse that list of files to get just the file names (the last column) inside a list? See the link above for example output.
Using retrlines() probably isn't the best idea there, since it just prints to the console and so you'd have to do tricky things to even get at that output. A likely better bet would be to use the nlst() method, which returns exactly what you want: a list of the file names.
This best answer
You may want to use ftp.nlst() instead of ftp.retrlines(). It will give you exactly what you want.
If you can't, read the following :
Generators for sysadmin processes
In his now famous review, Generator Tricks For Systems Programmers An Introduction, David M. Beazley gives a lot of receipes to answer to this kind of data problem with wuick and reusable code.
E.G :
# empty list that will receive all the log entry
log = []
# we pass a callback function bypass the print_line that would be called by retrlines
# we do that only because we cannot use something better than retrlines
ftp.retrlines('LIST', callback=log.append)
# we use rsplit because it more efficient in our case if we have a big file
files = (line.rsplit(None, 1)[1] for line in log)
# get you file list
files_list = list(files)
Why don't we generate immediately the list ?
Well, it's because doing it this way offer you much flexibility : you can apply any intermediate generator to filter files before turning it into files_list : it's just like pipe, add a line, you add a process without overheat (since it's generators). And if you get rid off retrlines, it still work be it's even better because you don't store the list even one time.
EDIT : well, I read the comment to the other answer and it says that this won't work if there is any space in the name.
Cool, this will illustrate why this method is handy. If you want to change something in the process, you just change a line. Swap :
files = (line.rsplit(None, 1)[1] for line in log)
and
# join split the line, get all the item from the field 8 then join them
files = (' '.join(line.split()[8:]) for line in log)
Ok, this may no be obvious here, but for huge batch process scripts, it's nice :-)
And a slightly less-optimal method, by the way, if you're stuck using retrlines() for some reason, is to pass a function as the second argument to retrlines(); it'll be called for each item in the list. So something like this (assuming you have an FTP object named 'ftp') would work as well:
filenames = []
ftp.retrlines('LIST', lambda line: filenames.append(line.split()[-1]))
The list 'filenames' will then be a list of the file names.
Is there any reason why ftplib.FTP.nlst() won't work for you? I just checked and it returns only names of the files in a given directory.
Since every filename in the output starts at the same column, all you have to do is get the position of the dot on the first line:
drwxrwsr-x 5 ftp-usr pdmaint 1536 Mar 20 09:48 .
Then slice the filename out of the other lines using the position of that dot as the starting index.
Since the dot is the last character on the line, you can use the length of the line minus 1 as the index. So the final code is something like this:
lines = ftp.retrlines('LIST')
lines = lines.split("\n") # This should split the string into an array of lines
filename_index = len(lines[0]) - 1
files = []
for line in lines:
files.append(line[filename_index:])
If the FTP server supports the MLSD command, then please see section “single directory case” from that answer.
Use an instance (say ftpd) of the FTPDirectory class, call its .getdata method with connected ftplib.FTP instance in the correct folder, then you can:
directory_filenames= [ftpfile.name for ftpfile in ftpd.files]
I believe it should work for you.
file_name_list = [' '.join(each_file.split()).split()[-1] for each_file_detail in file_list_from_log]
NOTES -
Here I am making a assumption that you want the data in the program (as list), not on console.
each_file_detail is each line that is being produced by the program.
' '.join(each_file.split())
To replace multiple spaces by 1 space.