Tuple unpacking - python

I have a tuple that looks like this:
('Elizabeth', 'Peter, Angela, Thomas')
How could I separate the last value in it so it would look like this:
('Elizabeth', 'Peter', 'Angela', 'Thomas')

>>> names = ('Elizabeth', 'Peter, Angela, Thomas')
>>> [y for x in names for y in x.split(', ')]
['Elizabeth', 'Peter', 'Angela', 'Thomas']
There's also this way, I prefer the first however:
>>> ', '.join(names).split(', ')
['Elizabeth', 'Peter', 'Angela', 'Thomas']
Of course you can convert the result to a tuple in the end but it is most likely unnecessary to do so.

Related

Python Array Variable Assign

I have the following array in Python in the following format:
Array[('John', '123'), ('Alex','456'),('Nate', '789')]
Is there a way I can assign the array variables by field as below?
Name = ['john', 'Alex', 'Nate']
ID = ['123', '456', '789']
In the spirit of "explicit is better than implicit":
data = [('John', '123'), ('Alex', '456'), ('Nate', '789')]
names = [x[0] for x in data]
ids = [x[1] for x in data]
print(names) # prints ['John', 'Alex', 'Nate']
print(ids) # prints ['123', '456', '789']
Or even, to be even more explicit:
data = [('John', '123'), ('Alex', '456'), ('Nate', '789')]
NAME_INDEX = 0
ID_INDEX = 1
names = [x[NAME_INDEX] for x in data]
ids = [x[ID_INDEX] for x in data]
this is a compact way to do this using zip:
lst = [('John', '123'), ('Alex','456'),('Nate', '789')]
name, userid = list(zip(*lst))
print(name) # ('John', 'Alex', 'Nate')
print(userid) # ('123', '456', '789')
note that the results are stored in (immutable) tuples; if you need (mutatble) lists you need to cast.

Python - Use a list containing keys to make a dictionary out of a string

With something like this:
keys = ["Name:", "Date:", "Time:sec:", "Room"]
string = "Name:BobDate:1/3Time:sec:3:00:00RoomA1"
How can I get a dictionary like:
dict1 = {"Name" : "Bob", "Date" : "1/3", "Time:sec" : "3:00:00", "Room" : "A1"}
Removing the colon is optional.
I am able to remove keys from the string entirely using re.split(), .join(), and map() but I want to create a dictionary instead.
Just a regex way...
dict(zip(keys, re.match('(.*)'.join(keys + [""]), string).groups()))
Demo:
>>> if 1:
import re
keys = ["Name:", "Date:", "Time:sec:", "Room"]
string = "Name:BobDate:1/3Time:sec:3:00:00RoomA1"
dict(zip(keys, re.match('(.*)'.join(keys + [""]), string).groups()))
{'Name:': 'Bob', 'Date:': '1/3', 'Time:sec:': '3:00:00', 'Room': 'A1'}
Given your input:
keys = ["Name:", "Date:", "Time:sec:", "Room"]
string = "Name:BobDate:1/3Time:sec:3:00:00RoomA1"
You can split it using a regular expression preserving the split key itself, eg:
split = re.split('({})'.format('|'.join(re.escape(k) for k in keys)), string)
# ['', 'Name:', 'Bob', 'Date:', '1/3', 'Time:sec:', '3:00:00', 'Room', 'A1']
Then, use dict with zipping the appropriate slices (we start from 1 because of the leading empty match), eg:
dct = dict(zip(split[1::2], split[2::2]))
# {'Date:': '1/3', 'Name:': 'Bob', 'Time:sec:': '3:00:00', 'Room': 'A1'}
Using .split() in a loop works:
keys = ["Name:", "Date:", "Time:sec:", "Room"]
s = "Name:BobDate:1/3Time:sec:3:00:00RoomA1"
values = []
temp = s.split(keys[0])[-1]
for key in keys[1:]:
val, temp = temp.split(key)
values.append(val)
values.append(temp)
dict1 = dict(zip(keys, values))
print(dict1)
Output:
{'Name:': 'Bob', 'Date:': '1/3', 'Time:sec:': '3:00:00', 'Room': 'A1'}
One line approach,
In [40]: dict(zip(keys,[string.split(j)[-1].split(keys[-1])[0] if i == (len(keys) - 1) else string.split(j)[-1].split(keys[i+1])[0] for i,j in enumerate(keys)]))
Out[40]: {'Date:': '1/3', 'Name:': 'Bob', 'Room': 'A1', 'Time:sec:': '3:00:00'}
I know it's pretty complex approach :), Just to show the different option of answer.
We could replace the keys in string with a rowbreak (something to split by). And then perform a dict(zip(...
keys = ["Name:", "Date:", "Time:sec:", "Room"]
string = "Name:BobDate:1/3Time:sec:3:00:00RoomA1"
for key in keys:
string = string.replace(key,"\n")
d = dict(zip(keys,string.split('\n')[1:])) # 1: to handle first row break
d equals:
{'Date:': '1/3', 'Name:': 'Bob', 'Room': 'A1', 'Time:sec:': '3:00:00'}
You can try this:
import re
keys = ["Name:", "Date:", "Time:sec:", "Room"]
string = "Name:BobDate:1/3Time:sec:3:00:00RoomA1"
new_data = dict(zip(map(lambda x:x[:-1], keys), filter(None, re.split('\*', re.sub('|'.join(keys), '*', string)))))
Output:
{'Date': '1/3', 'Time:sec': '3:00:00', 'Name': 'Bob', 'Roo': 'A1'}
Here is my journey on finding the answer
In [17]: import re
In [18]: keys = ["Name:", "Date:", "Time:sec:", "Room"]
In [19]: string = "Name:BobDate:1/3Time:sec:3:00:00RoomA1"
In [20]: separators = '|'.join(keys)
In [21]: separators
Out[21]: 'Name:|Date:|Time:sec:|Room'
In [22]: re.split(separators, string)
Out[22]: ['', 'Bob', '1/3', '3:00:00', 'A1']
In [23]: re.split(separators, string)[1:]
Out[23]: ['Bob', '1/3', '3:00:00', 'A1']
In [24]: values = re.split(separators, string)[1:]
In [25]: dict(zip(keys, values))
Out[25]: {'Date:': '1/3', 'Name:': 'Bob', 'Room': 'A1', 'Time:sec:': '3:00:00'}
In [26]: dict1 = dict(zip(keys, values))
Notes
Line 20, 21: Create a list of separators to use in re.split later on. The pipe symbol (|) means "or" in regular expression
Line 22: Split the string using this list of separators. We almost got what we want except for the first element that is blank
Line 23 fixes that first blank element
Line 24, with that, we assign the result to values, to be used later to construct the dictionary
Line 25, 26: Construct that dictionary and assign to dict1

Appending certain elements from a list of list into another list

I have a nested list as shown below:
L = [['James', 'Bob', '23', '47'], ['Earl', 'Carl', '16', '43'], ['Milly', 'Wendy', '1', '21']]
I want to take the names from each of them and put them into a new list called 'newList' without the numbers.
I tried the following code:
for i in L[0][0]:
newList.append(i)
print(newList)
However, this just printed the first name and each letter was seperated by a comma. I want the new list to look like this:
newList = ['James', 'Bob', 'Earl', 'Carl', 'Milly', 'Wendy']
Just use a nested list comprehension:
In [61]: [i for sub in L for i in sub[:2]]
Out[61]: ['James', 'Bob', 'Earl', 'Carl', 'Milly', 'Wendy']
You need to iterate over elements in list L
for i in L:
newList.append(i[0])
newList.append(i[1])
#or simply newList.extend(i[:2])
print(newList)
EDIT
for i in L:
if i[0] not in newList:
newList.append(i[0])
if i[1] not in newList:
newList.append(i[1])
#or simply newList.extend(i[:2])
print(newList)
You can use isdigit() to filter out names
res = [j for i in L for j in i if not j.isdigit()]
['James', 'Bob', 'Earl', 'Carl', 'Milly', 'Wendy']
Do it in two steps.
First, grab the first two elements of each list:
>>> names_nested = [sub[:2] for sub in L]
>>> names_nested
[['James', 'Bob'], ['Earl', 'Carl'], ['Milly', 'Wendy']]
Then unnest this list:
>>> names = [name for sub in names_nested for name in sub]
>>> names
['James', 'Bob', 'Earl', 'Carl', 'Milly', 'Wendy']
... or do it more comfortably with itertools.chain:
>>> from itertools import chain
>>> list(chain(*(sub[:2] for sub in L)))
['James', 'Bob', 'Earl', 'Carl', 'Milly', 'Wendy']
... or itertools.chain.from_iterable to get rid of the unpacking star and one set of parentheses.
>>> list(chain.from_iterable(sub[:2] for sub in L))
['James', 'Bob', 'Earl', 'Carl', 'Milly', 'Wendy']
If the problem is simply the first two elements from each sublist you can do:
from itertools import chain
result = chain.from_iterable(sublist[:2] for sublist in L)
This will produce a chain object, you can use list to evaluate it:
list(result)
# ['James', 'Bob', 'Earl', 'Carl', 'Milly', 'Wendy']
Using numpy to slice the list and flatten the results to a 1D list:
import numpy as np
np.array(L)[:,0:2].flatten().tolist()
Out[349]: ['James', 'Bob', 'Earl', 'Carl', 'Milly', 'Wendy']
Use the isdigit method to see if a str is a digit:
[j for l in L for j in l if not j.isdigit()]
Output:
['James', 'Bob', 'Earl', 'Carl', 'Milly', 'Wendy']

Change a list to a string with specific formatting

Let's say that I have a list of names:
names = ['john', 'george', 'ringo', 'paul']
And need to get a string output like:
john', 'george', 'ringo', 'paul
(Note that the missing quote at the beginning and at the end is on purpose)
Is there an easier way to do this than
new_string=''
for x in names:
new_string = new_string + x + "', '"
I know something like that will work, however the real names list will be very very (very) big and was wondering if there is a nicer way to do this.
You can simply use str.join:
>>> names = ['john', 'george', 'ringo', 'paul']
>>> print("', '".join(names))
john', 'george', 'ringo', 'paul
>>>
may be bad way to do it, just wana share it :
>>> names = ['john', 'george', 'ringo', 'paul']
>>> print(str(names)[2:-2])
john', 'george', 'ringo', 'paul

How to erase duplicated element in row of a list in python

I don't know exactly how to explain this for the title, so here some code to express what I need. I have a list like this:
lst = [['24', 'john', 'july, 'email#gmail.com],
['12', 'alice', 'auguts, 'email#hotmail.com],
['48', 'john', 'september, 'email#outlook.com],
[ ....]]
I want to erase all duplicated sublists with the same name (name being the second field in each sublist), in this case I want the final list to be:
lst = [['24', 'john', 'july, 'email#gmail.com],
['12', 'alice', 'auguts, 'email#hotmail.com]
[ ....]]
I don't want to find a duplicated list and erase it, I want to erase a list which has a duplicated field. Sorry if I didn't explain myself well.
Thanks!
Use set to check duplicates.
>>> lst = [
... ['24', 'john', 'july', 'email#gmail.com'],
... ['12', 'alice', 'auguts', 'email#hotmail.com'],
... ['48', 'john', 'september', 'email#outlook.com'],
... ]
>>>
>>> seen = set()
>>> result = []
>>> for item in lst:
... name = item[1]
... if name not in seen:
... seen.add(name)
... result.append(item)
...
>>> result
[['24', 'john', 'july', 'email#gmail.com'],
['12', 'alice', 'auguts', 'email#hotmail.com']]
Don't use list as a variable name. It shadows builtin list.
>>> seen = set()
>>> [x for x in lst if (x[1] not in seen, seen.add(x[1]))[0]]
[['24', 'john', 'july', 'email#gmail.com'],
['12', 'alice', 'auguts', 'email#hotmail.com']]
Using filter:
lst = [['24', 'john', 'july', 'email#gmail.com'],
['12', 'alice', 'auguts', 'email#hotmail.com'],
['48', 'john', 'september', 'email#outlook.com']
]
seen = {}
def filter_condition(item):
if item[1] in seen: return False
seen[item[1]] = 1
return True
print filter(filter_condition, lst)
Here's a naive approach, renaming your starting list to oldlist to avoid a naming problem with the builtin Python list.
newlist = []
for j, sublist in enumerate(oldlist):
unique = True
for laterlist in oldlist[j+1:]:
if any([sublist[k] == laterlist[k] for k in range(len(sublist))]):
unique = False
if unique:
newlist.append(sublist)

Categories

Resources