Related
I have a list l:
l = ['Abc.xlsx', 'Wqe.csv', 'Abc.csv', 'Xyz.xlsx']
In this list, I need to remove duplicates without considering the extension. The expected output is below.
l = ['Wqe.csv', 'Abc.csv', 'Xyz.xlsx']
I tried:
l = list(set(x.split('.')[0] for x in l))
But getting only unique filenames without extension
How could I achieve it?
You can use a dictionary comprehension that uses the name part as key and the full file name as the value, exploiting the fact that dict keys must be unique:
>>> list({x.split(".")[0]: x for x in l}.values())
['Abc.csv', 'Wqe.csv', 'Xyz.xlsx']
If the file names can be in more sophisticated formats (such as with directory names, or in the foo.bar.xls format) you should use os.path.splitext:
>>> import os
>>> list({os.path.splitext(x)[0]: x for x in l}.values())
['Abc.csv', 'Wqe.csv', 'Xyz.xlsx']
If the order of the end result doesn't matter, we could split each item on the period. We'll regard the first item in the list as the key and then keep the item if the key is unique.
oldList = l
setKeys = set()
l = []
for item in oldList:
itemKey = item.split(".")[0]
if itemKey in setKeys:
pass
else:
setKeys.add(itemKey)
l.append(item)
Try this
l = ['Abc.xlsx', 'Wqe.csv', 'Abc.csv', 'Xyz.xlsx']
for x in l:
name = x.split('.')[0]
find = 0
for index,d in enumerate(l, start=0):
txt = d.split('.')[0]
if name == txt:
find += 1
if find > 1:
l.pop(index)
print(l)
#Selcuk Definitely the best solution, unfortunately I don't have enough reputation to vote you answer.
But I would rather use el[:el.rfind('.')] as my dictionary key than os.path.splitext(x)[0] in order to handle the case where we have sophisticated formats in the name. that will give something like this:
list({x[:x.rfind('.')]: x for x in l}.values())
I am trying to convert string into Dictionary in Python. I have tried the following but getting the error
'dict' object is not callable. Please help me solve this problem.
l=[]
str='Vijay=23,Ganesh=20,Lakshmi=19,Nikhil=22'
for x in str.split(','):
y=x.split('=')
l.append(y)
d=dict(l)
for k in d:
print('{:1s}---{:1s}'.format(k,d[k]))
s = 'Vijay=23,Ganesh=20,Lakshmi=19,Nikhil=22'
dct = {n: a for n, a in (p.split("=") for p in s.split(","))} #Credits to JL0PD
print(dct)
#{'Vijay': '23', 'Ganesh': '20', 'Lakshmi': '19', 'Nikhil': '22'}
l=[]
str='Vijay=23,Ganesh=20,Lakshmi=19,Nikhil=22'
for x in str.split(','):
y=x.split('=')
l.append(y)
result = {}
for item in l:
result[item[0]] = item[1]
print(result)
You override the reserved word str.
In python the word str is the name of the class string.
When you wrote str = 'Vijay=23,Ganesh=20,Lakshmi=19,Nikhil=22',
you changed the class str to be 'Vijay=23,Ganesh=20,Lakshmi=19,Nikhil=22'
run this code:
l = []
string = 'Vijay=23,Ganesh=20,Lakshmi=19,Nikhil=22'
for x in string.split(','):
y = x.split('=')
l.append(y)
d = dict(l)
for k in d:
print('{:1s}---{:1s}'.format(k,d[k]))
Same code but follows PEP8 rules
pars_list = []
row_data = 'Vijay=23,Ganesh=20,Lakshmi=19,Nikhil=22'
for i in row_data.split(','):
pars_list.append(i.split('='))
data = dict(l)
for k in data.keys():
print('{:1s}---{:1s}'.format(k, data[k]))
Give this a try.
Step1
Iterate through ['Vijay=23', 'Ganesh=20', 'Lakshmi=19', 'Nikhil=22']
Step2
Split every person by =. ['Nikhil', '22']
Step3
Add the first element to the dict as a key and the age to the dict as a value
peopleDict = {people.split('=')[0]:int(people.split('=')[1]) for people in string.split(',')}
output
{'Vijay': 23, 'Ganesh': 20, 'Lakshmi': 19, 'Nikhil': 22}
#Note1: Make sure you do not name your variable str or int, input etc. These are all methods created by python, don't overide them.
#Note2: my output turns all the ages into integers just in case you need to manipulate them later on in your code.
I have the following list and am wanting to convert it into a dictionary where the 4 digit value at the start of each item becomes the id.
['3574,A+,2021-03-24', '3575,O+,2021-04-03', '3576,AB-,2021-04-09', '3580,AB+,2021-04-27', '3589,A+,2021-05-08', '3590,B-,2021-05-11']
I have tried many different methods but it doesn't seem to work.
You can use str.split, map and dictionary comprehension
# data holds the list you have provided
{splitted[0]:splitted[1:] for splitted in map(lambda item:item.split(','), data)}
OUTPUT:
Out[35]:
{'3574': ['A+', '2021-03-24'],
'3575': ['O+', '2021-04-03'],
'3576': ['AB-', '2021-04-09'],
'3580': ['AB+', '2021-04-27'],
'3589': ['A+', '2021-05-08'],
'3590': ['B-', '2021-05-11']}
You can use dictionary comprehension with str.split:
lst = [
"3574,A+,2021-03-24",
"3575,O+,2021-04-03",
"3576,AB-,2021-04-09",
"3580,AB+,2021-04-27",
"3589,A+,2021-05-08",
"3590,B-,2021-05-11",
]
out = {int(v.split(",")[0]): v.split(",")[1:] for v in lst}
print(out)
Prints:
{
3574: ["A+", "2021-03-24"],
3575: ["O+", "2021-04-03"],
3576: ["AB-", "2021-04-09"],
3580: ["AB+", "2021-04-27"],
3589: ["A+", "2021-05-08"],
3590: ["B-", "2021-05-11"],
}
Here is the code to do what I believe you asked for. I have also added comments in the code for a bit more clarification.
my_list = ['3574,A+,2021-03-24',
'3575,O+,2021-04-03',
'3576,AB-,2021-04-09',
'3580,AB+,2021-04-27',
'3589,A+,2021-05-08',
'3590,B-,2021-05-11']#your list
my_dict = {}#The dictionary you want to put the list into
print("Your list:", my_list, "\n")
for item in my_list:#cycles through every item in your list
ID, value = item.split(",", 1)#Splits the item in your list only once (when it sees the first comma)
print(ID + ": " + value)
my_dict[ID] = value#Add the ID and value to your dictionary
print("\n" + "Your desired dictionary:", my_dict)
Which outputs this:
Your list: ['3574,A+,2021-03-24', '3575,O+,2021-04-03', '3576,AB-,2021-04-09', '3580,AB+,2021-04-27', '3589,A+,2021-05-08', '3590,B-,2021-05-11']
3574: A+,2021-03-24
3575: O+,2021-04-03
3576: AB-,2021-04-09
3580: AB+,2021-04-27
3589: A+,2021-05-08
3590: B-,2021-05-11
Your desired dictionary: {'3574': 'A+,2021-03-24', '3575': 'O+,2021-04-03', '3576': 'AB-,2021-04-09', '3580': 'AB+,2021-04-27', '3589': 'A+,2021-05-08', '3590': 'B-,2021-05-11'}
Enjoy!
TRY:
result = dict(i.split(',', 1) for i in lst)
OUTPUT:
{'3574': 'A+,2021-03-24',
'3575': 'O+,2021-04-03',
'3576': 'AB-,2021-04-09',
'3580': 'AB+,2021-04-27',
'3589': 'A+,2021-05-08',
'3590': 'B-,2021-05-11'}
Say I have a dictionary with keys being a category name and values being words within that category. For example:
words={
'seasons':('summer','spring','autumn','winter'),
'rooms':('kitchen','loo','livingroom','hall','diningroom','bedroom'),
'insects':('bee','butterfly','beetle')}
For any given input I want to create a list with two items where the first item is the value word and the second is the key word. For example, the expected output should be:
input: kitchen
output: ['kitchen','rooms']
input: bee
output: ['bee','insects']
I checked the question Get key by value in dictionary but afaict all answers work for dictionaries with 1 value per key.
I've tried the following naive, closed form code:
word=input('Enter a word: ')
word_pair=[]
word_pair.append(word)
if word in (words['seasons']):
index=0
elif word in (words['rooms']):
index=1
elif word in (words['insects']):
index=2
else:
index=3
try:
key_val=list(words.keys())[index]
word_pair.append(key_val)
except IndexError:
word_pair.append('NA')
print(word_pair)
Obviously, this code only works for this specific dictionary as is. If I wanted to add a category, I'd have to add an elif clause. If I wanted to change the name of a category or their order, remove one, combine two or more, etc., I'd have to tweak a whole bunch of things by hand.
Is there a more generalized way to do this?
All help is appreciated.
You can use generator with unpacking:
inp = input()
result, *_ = ([inp, k] for k, v in words.items() if inp in v)
Even better to use next() with generator, cause it will stop after first match found:
result = next([inp, k] for k, v in words.items() if inp in v)
You can invert that dict with:
>>> {s_v:k for k,v in words.items() for s_v in v}
{'summer': 'seasons', 'spring': 'seasons', 'autumn': 'seasons', 'winter': 'seasons', 'kitchen': 'rooms', 'loo': 'rooms', 'livingroom': 'rooms', 'hall': 'rooms', 'diningroom': 'rooms', 'bedroom': 'rooms', 'bee': 'insects', 'butterfly': 'insects', 'beetle': 'insects'}
And then lookup your input in the inverted dict.
You can do it like this:
words={
'seasons':('summer','spring','autumn','winter'),
'rooms':('kitchen','loo','livingroom','hall','diningroom','bedroom'),
'insects':('bee','butterfly','beetle')}
def find_cat(word):
for category, items in words.items():
if word in items:
return category
word=input('Enter a word: ')
print(find_cat(word))
Explanation: words.items() return a tuple (key, value) for each key in the dictionary. In this case, value is a list. So, we can use the in operator to find if the word is in that list. If yes, simply return the key.
You can iterate over the dictionary keys:
words={
'seasons':('summer','spring','autumn','winter'),
'rooms':('kitchen','loo','livingroom','hall','diningroom','bedroom'),
'insects':('bee','butterfly','beetle')}
search_text = input("input: ")
for key in words.keys():
if search_text in words[key]:
print("output: {0}".format([search_text,key]))
You would test using in rather than exact match (see word in value in the code below), and you'd probably also want to include some kind of check that there is only one matching key, and provided that there is, use the first one.
words = {
'seasons':('summer','spring','autumn','winter'),
'rooms':('kitchen','loo','livingroom','hall','diningroom','bedroom'),
'insects':('bee','butterfly','beetle')}
word = 'kitchen'
keys = [key for key, value in words.items() if word in value]
if len(keys) != 1:
raise ValueError
word_pair = [word, keys[0]]
print(word_pair)
Gives:
['kitchen', 'rooms']
Another way to do it would be to transform your input dictionnary to inverse the logic: make values the keys, and the keys, values.
So a solution like that one:
def invert_dic(index):
new_dic = {}
for k,v in index.items():
for x in v:
new_dic.setdefault(x,[]).append(k)
and then you'd do:
index = invert_dic(words) # linear time, O(n)
word = input('Enter a word: ')
categories = index.get(word, ['None'])) # constant time, O(1)
print(', '.join(f"Your word is in those categories: {categories}")
That solution is mimicking the concept of indexes in databases, where you spend time at the creation of the database (the words dictionary being converted as the index dictionary) and memory to store that index, to have very fast resolution when looking up a word using the hash algorithm (where looking a key is in constant time).
A bonus of the above solution is that if a word is in two categories, you'll get the list of all the categories your word is in.
I am trying to replace the valuse in a list with the long format name.
value_list = ['Gi1/0/8', 'Gi1/0/31', 'Gi1/0/32', 'Gi1/0/33', 'Gi1/0/34', 'Gi1/0/23', 'Gi1/0/27']
I am running the following script:
for value in value_list:
value = re.sub(r'Gi', 'GigabitEthernet', value)
print value
print value_list
This is my out put:
GigabitEthernet1/0/8
GigabitEthernet1/0/31
GigabitEthernet1/0/32
GigabitEthernet1/0/33
GigabitEthernet1/0/34
GigabitEthernet1/0/23
GigabitEthernet1/0/27
I just need to change the values in the list, it seems doing it all wrong. Can anyone help me do this in an efficient manner so i dont need to create another list from the individual outputs??
Then use list comprehension instead:
print([re.sub(r'Gi', 'GigabitEthernet', value) for value in value_list])
Output:
['GigabitEthernet1/0/8', 'GigabitEthernet1/0/31', 'GigabitEthernet1/0/32', 'GigabitEthernet1/0/33', 'GigabitEthernet1/0/34', 'GigabitEthernet1/0/23', 'GigabitEthernet1/0/27']
This code updates existing list:
value_list = ['Gi1/0/8', 'Gi1/0/31', 'Gi1/0/32', 'Gi1/0/33', 'Gi1/0/34', 'Gi1/0/23', 'Gi1/0/27']
for i in range(len(value_list)):
value_list[i] = re.sub(r'Gi', 'GigabitEthernet', value_list[i])
print value_list
# ['GigabitEthernet1/0/8', 'GigabitEthernet1/0/31', 'GigabitEthernet1/0/32', 'GigabitEthernet1/0/33', 'GigabitEthernet1/0/34', 'GigabitEthernet1/0/23', 'GigabitEthernet1/0/27']
Using map
Ex:
import re
value_list = ['Gi1/0/8', 'Gi1/0/31', 'Gi1/0/32', 'Gi1/0/33', 'Gi1/0/34', 'Gi1/0/23', 'Gi1/0/27']
value_list = list(map(lambda value: re.sub(r'Gi', 'GigabitEthernet', value), value_list))
print(value_list)
Output:
['GigabitEthernet1/0/8', 'GigabitEthernet1/0/31', 'GigabitEthernet1/0/32', 'GigabitEthernet1/0/33', 'GigabitEthernet1/0/34', 'GigabitEthernet1/0/23', 'GigabitEthernet1/0/27']
To change the list "in-place" you need to set each item in the list to the new value. Just doing value = re.sub(r'Gi', 'GigabitEthernet', item) doesn't change the value stored in the list.
This code changes the values in the list:
>>> value_list = ['Gi1/0/8', 'Gi1/0/31', 'Gi1/0/32', 'Gi1/0/33', 'Gi1/0/34', 'Gi1/0/23', 'Gi1/0/27']
>>> for idx, item in enumerate(value_list):
... value_list[idx] = re.sub(r'Gi', 'GigabitEthernet', item)
...
>>> value_list
['GigabitEthernet1/0/8', 'GigabitEthernet1/0/31', 'GigabitEthernet1/0/32', 'GigabitEthernet1/0/33', 'GigabitEthernet1/0/34', 'GigabitEthernet1/0/23', 'GigabitEthernet1/0/27']
The enumerate function generates the list indexes for you, so you can iterate over your list pythonically (for item in mylist) rather than indexing directly (for i in range(len(mylist))) which produces less readable code.