Can this for loop be reduced to one line? - python

Python code:
arr = [['name1', 101], ['name2', 234], ['name3', 456]]
nametolookfor = input("Please enter the name: ")
data = 0
for value in arr:
if value[0] == nametolookfor:
otherdata = value[1]
I was wondering if the for loop and its contents could be brought down to one line.
I have tried using list comprehensions but can't seem to get it to work.

You can use a list comprehension to filter for array elements where the name matches, then select only the value, and from that retrieve the first:
>>> arr = [['name1', 101], ['name2', 234], ['name3', 456]]
>>> nametolookfor = 'name2'
>>> [v for (n, v) in arr if n == nametolookfor][0]
234
Since your list is a list of key/value pairs where the key is (by definition) unique, you can also make it into a dictionary and have a direct lookup instead:
>>> lookup = dict(arr)
>>> lookup[nametolookfor]
234
Of course, if your arr is static, you can just declare it as a dictionary from the start to save you from having to do the conversion:
>>> lookup = { 'name1': 101, 'name2': 234, 'name3': 456 }
>>> lookup[nametolookfor]
234

I think this should be close to what you want. Using next avoids some boilerplate later to check if the value exists.
next(value[0] for value in are if value[0] == nametolookfor, None)

Yes this is posible in list comprehensions. Follow this
[value[1] for value in arr if value[0] == nametolookfor]
Please enter the name: name1
Output: [101]
Assume your list arr = [['name1', 101], ['name2', 234], ['name3', 456], ['name1', 202], ['name1', 303]] and set input nametolookfor = name1 then result will be
[101, 202, 303]

Try this out:
otherdata = dict(arr)[nametolookfor]
Since the list is a list of key/value pairs where the key is unique, you can convert it into a dictionary and have a direct lookup.

Related

Python - How to replace an element at a specific position in a 2d list [duplicate]

aList = [123, 'xyz', 'zara', 'abc']
aList.append(2014)
print aList
which produces o/p [123, 'xyz', 'zara', 'abc', 2014]
What should be done to overwrite/update this list.
I want the o/p to be
[2014, 'xyz', 'zara', 'abc']
You may try this
alist[0] = 2014
but if you are not sure about the position of 123 then you may try like this:
for idx, item in enumerate(alist):
if 123 in item:
alist[idx] = 2014
What about replace the item if you know the position:
aList[0]=2014
Or if you don't know the position loop in the list, find the item and then replace it
aList = [123, 'xyz', 'zara', 'abc']
for i,item in enumerate(aList):
if item==123:
aList[i]=2014
break
print aList
I think it is more pythonic:
aList.remove(123)
aList.insert(0, 2014)
more useful:
def shuffle(list, to_delete, to_shuffle, index):
list.remove(to_delete)
list.insert(index, to_shuffle)
return
list = ['a', 'b']
shuffle(list, 'a', 'c', 0)
print list
>> ['c', 'b']
I'm learning to code and I found this same problem. I believe the easier way to solve this is literaly overwriting the list like #kerby82 said:
An item in a list in Python can be set to a value using the form
x[n] = v
Where x is the name of the list, n is the index in the array and v is the value you want to set.
In your exemple:
aList = [123, 'xyz', 'zara', 'abc']
aList[0] = 2014
print aList
>>[2014, 'xyz', 'zara', 'abc']
I would prefer it without enumerate and instead use "range" like this:
for item in range(0, len(alist)):
if 123 in alist[item]:
alist[item] = 2014
For those who are new to python it might be more readable and a little smarter to recap.
Regards P.
If you are trying to take a value from the same array and trying to update it, you can use the following code.
{ 'condition': {
'ts': [ '5a81625ba0ff65023c729022',
'5a8161ada0ff65023c728f51',
'5a815fb4a0ff65023c728dcd']}
If the collection is userData['condition']['ts'] and we need to
for i,supplier in enumerate(userData['condition']['ts']):
supplier = ObjectId(supplier)
userData['condition']['ts'][i] = supplier
The output will be
{'condition': { 'ts': [ ObjectId('5a81625ba0ff65023c729022'),
ObjectId('5a8161ada0ff65023c728f51'),
ObjectId('5a815fb4a0ff65023c728dcd')]}

How to convert a nested list into a dictionary?

I would like to take a nested list such as:
list = [[Name, Height, Weight],[Dan, 175, 75],[Mark, 165, 64], [Sam, 183, 83]]
and convert it into a dictionary like:
dict = {Name: [Dan,Mark, Sam], Height: [175, 165, 183], Weight: [75, 64, 83]}
my current code is unfortunately not really giving me the dictionary format I'm looking for.
i = 1
z = 0
for items in list[0]:
dict[items] = [list[i][z]]
i += 1
z += 1
can someone please assist me and find where I'm going wrong?
Separate the keys and the rest first, then construct the dictionary with zip:
keys, *rest = list_of_lists
out = dict(zip(keys, zip(*rest)))
where list_of_lists is what you called list (but please refrain from that as it shadows the builtin list). First * is slurping all the lists starting from second one. The second * in zip kind of transposes the lists to reorder them
to get
>>> out
{"Name": ("Dan", "Mark", "Sam"),
"Height": (175, 165, 183),
"Weight": (75, 64, 83)}
this gives tuples in the values but to get lists, you can map:
out = dict(zip(keys, map(list, zip(*rest))))
Welcome to stackoverflow :)
We seldom use i++ i+=1 for loop count or step in python if we can easily use for i in ... even if we don't know how many list in it.
your original data is a list of list. first list is the key of dictionary, other list is each records.
we often use zip(*your_list) when your data (list in list) is equal length. zip function will help you rearrange your_list. the * in front of your_list means put each record in your_list to zip function's argument one by one
then put it in a for loop, like for rec in zip(list):.
so, you can write your code like:
your_dict = {}
for rec in zip(yout_list):
k = rec[0] #dict key
v = list(rec[1:]) #dict value, convert to list if needed
your_dict[k] = v # set key and value
e.g.
that's it!
#Mustafa's answer is the most concise but if you are a beginner you might find it easier to break it down into steps.
data =[
['Name', 'Height', 'Weight'],
['Dan', 175, 75], ['Mark', 165, 64], ['Sam', 183, 83]
]
keys = data[0]
values = [list(items) for items in zip(*data[1:])]
results = dict(zip(keys, values))

Convert List to Rows

What is an efficient way to convert a list into separate elements in python?
I have a dataset that looks like this;
['StudentA','80','94','93']
['StudentB','93','94']
I would like to reshape the data so that each student/score has its own row;
['StudentA','80']
['StudentA','94']
etc...
You could use a list comprehension, like this:
data = ['StudentA','80','94','93']
res = [[data[0], x] for x in data[1:]]
This sets res to [['StudentA', '80'], ['StudentA', '94'], ['StudentA', '93']].
c=['StudentA','80','94','93']
d=[[c[0], p] for p in c[1:]]
This dict comprehension will group you data by student name:
d = {x[0]: x[1:] for x in dataset}
i.e.:
>>> d
{'StudentA': ['80', '94', '93'], 'StudentB': ['93', '94']}
from which you can extract individual pairs with a nested for loop or list comprehension:
>>> [(k, w) for k, v in d.items() for w in v]
[('StudentA', '80'), ('StudentA', '94'), ('StudentA', '93'), ('StudentB', '93'), ('StudentB', '94')]
If it were a list (all_students) containing each of these lines, you could do what you want, by doing :
result = []
for student in all_students:
student_name = student[0]
result.extend([[student_name, value] for value in student[1:]]
print(result)
Couple student with it's respective data using a dictionary.
def to_dict(l):
d = {}
for i in l:
key = i[0]
value = i[1:]
d[key] = value
return d
Sample output:
l = [['studentA', 90, 90],['studentB', 78, 40]]
print to_dict(l)
>>> {'studentB': [78, 40], 'studentA': [90, 90]}
for key, value in d.iteritems():
for i in value:
print key, i
>>> studentB 78
>>> studentB 40
>>> studentA 90
>>> studentA 90

How to create a new layer of sublists based on a common key within each sublist in order to categorize the sublists?

How to create a new layer of sublists based on a common key within each sublist in order to categorize the sublists? In other words, how do you place sublists into a new sublist within the list where each item at index 1 is the same?
For example, I'd like to turn the following list of sublists into a list of sublists in which each sublist is in a new sublist where each item at index 1 is the same within that sublist. I'd like to place the sublists of apples, bananas and oranges in this list into a new sublist.
lsta = [['2014W01','apple',21,'apple#gmail.com'],['2014W02','apple',19,'apple#g.com'],['2014W02','banana',51,'b#gmail.com'],['2014W03','apple',100,'apple#gmail.com'],['2014W01','banana',71,'b#yahoo.com'],['2014W02','organge',21,'organge#gmail.com']]
I'd like the three sublists of apples to be contained within a new sublist, as well as the two sublists of bananas into a new sublist, etc.
Desired_List = [[['2014W01','apple',21,'apple#gmail.com'],['2014W02','apple',19,'apple#g.com'],['2014W03','apple',100,'apple#gmail.com']],[['2014W02','banana',51,'b#gmail.com'],['2014W01','banana',71,'b#yahoo.com']],[['2014W02','organge',21,'organge#gmail.com']]]
Bonus points, if you could tell me how to do multiple categorizations (e.g. not only separating by fruit type, but also by week)?
In [43]: import itertools as IT
In [44]: import operator
In [46]: [list(grp) for key, grp in IT.groupby(sorted(lsta, key=operator.itemgetter(1)), key=operator.itemgetter(1))]
Out[46]:
[[['2014W01', 'apple', 21, 'apple#gmail.com'],
['2014W02', 'apple', 19, 'apple#g.com'],
['2014W03', 'apple', 100, 'apple#gmail.com']],
[['2014W02', 'banana', 51, 'b#gmail.com'],
['2014W01', 'banana', 71, 'b#yahoo.com']],
[['2014W02', 'organge', 21, 'organge#gmail.com']]]
Normally, I'd use itertools.groupby on this, but just for fun, here's a method that does all the heavy lifting manually
def transform(lista):
d = {}
for subl in lista:
k = subl.pop(1)
if k not in d:
d[k] = []
d[k].append(subl)
answer = []
for k, lists in d.items():
temp = []
for l in lists:
l.insert(1, k)
temp.append(l)
answer.append(temp)
return answer
Output:
In [56]: transform(lsta)
Out[56]:
[[['2014W02', 'organge', 21, 'organge#gmail.com']],
[['2014W01', 'apple', 21, 'apple#gmail.com'],
['2014W02', 'apple', 19, 'apple#g.com'],
['2014W03', 'apple', 100, 'apple#gmail.com']],
[['2014W02', 'banana', 51, 'b#gmail.com'],
['2014W01', 'banana', 71, 'b#yahoo.com']]]
I'll take a bit of a different tack. You probably want your group-by field to be the lookup value in a dict. The value can just be a list of various.. whatever you want to call each sublist here. I'll call each one a FruitPerson.
from collections import defaultdict, namedtuple
FruitPerson = namedtuple('FruitPerson','id age email')
d = defaultdict(list)
for sublist in lsta:
d[sublist[1]].append(FruitPerson(sublist[0],*sublist[2:]))
Then, for example:
d['apple']
Out[19]:
[FruitPerson(id='2014W01', age=21, email='apple#gmail.com'),
FruitPerson(id='2014W02', age=19, email='apple#g.com'),
FruitPerson(id='2014W03', age=100, email='apple#gmail.com')]
d['apple'][0]
Out[20]: FruitPerson(id='2014W01', age=21, email='apple#gmail.com')
d['apple'][0].id
Out[21]: '2014W01'
Edit: okay, multiple-categorization-bonus-point question. You just need to nest your dictionaries. The syntax gets a little goofy because the argument to defaultdict has to be a callable; you can do this with either lambda or functools.partial:
FruitPerson = namedtuple('FruitPerson','age email') #just removed 'id' field
d = defaultdict(lambda: defaultdict(list))
for sublist in lsta:
d[sublist[1]][sublist[0]].append(FruitPerson(*sublist[2:]))
d['apple']
Out[37]: defaultdict(<type 'list'>, {'2014W03': [FruitPerson(age=100, email='apple#gmail.com')], '2014W02': [FruitPerson(age=19, email='apple#g.com')], '2014W01': [FruitPerson(age=21, email='apple#gmail.com')]})
d['apple']['2014W01']
Out[38]: [FruitPerson(age=21, email='apple#gmail.com')]
d['apple']['2014W01'][0].email
Out[40]: 'apple#gmail.com'
Though honestly at this point you should consider moving up to a real relational database that can understand SELECT whatever FROM whatever WHERE something type queries.

Filtering a list based on a second list

Here is what is probably a simple question, but I wasn't able to find a straightforward answer for on my own.
Given two lists, one with only a list of ids, the other with all data, including some ids that we don't care about:
all_data = [['abc', 123], ['cde', 234], ['fgh', 345]]
ids = ['abc', 'fgh']
what is the best way to get the following output, note that it keeps only those that have the same ids:
new_data = [['abc', 123], ['fgh', 345]]
My current code does something like:
for x in all_data:
for y in ids:
if x[0] == y:
new_data.append(x)
What woud you do differently? Is there a built-in function that takes care of this that I missed somewhere?
(I say "something like" because it's actually a very long sequence involving sets and all that which is why there is not "pythonic" one-liner to share.)
UPDATE:
Well you guys are fun.
How about I make it a little harder. What if instead of "all_data" I have a a dictionary all_data_dict that has several list entries of the same format as "all_data"? Following the rules, I'll make sure to accept the answer to the original question, but if you all want to keep up with the fun, let's see what we get!
Use a list comprehension where the conditional checks for membership in a set:
>>> all_data = [['abc', 123], ['cde', 234], ['fgh', 345]]
>>> ids = ['abc', 'fgh']
>>> id_set = set(ids)
>>> [s for s in all_data if s[0] in id_set]
[['abc', 123], ['fgh', 345]]
Edited after the comment, I meant to use a set.
As Raymond suggests in his answer use a list comprehension :) with a set for ids.
all_data = [['abc', 123], ['cde', 234], ['fgh', 345]]
ids = set(['abc', 'fgh'])
filtered_data = [x for x in all_data if x[0] in ids]
being that many have used dicts or LC I thought I should show filter
>>> all_data = [['abc', 123], ['cde', 234], ['fgh', 345]]
>>> ids = set(['abc', 'fgh'])
>>> values = filter(lambda value: value[0] in ids, all_data)
>>> values
[['abc', 123], ['fgh', 345]]
>>>
as for the second part.
>>> all_data_dict = {'abc':all_data, 'cde':all_data, 'fgh':all_data}
>>> ids = set(['abc', 'fgh'])
>>> dict(filter(lambda value: value[0] in ids, all_data_dict.items()))
{'abc': [['abc', 123], ['cde', 234], ['fgh', 345]], 'fgh': [['abc', 123], ['cde', 234], ['fgh', 345]]}
You should turn all_data into a dictionary, since you use it like one:
d = dict(all_data)
new_data = [(k, d[k]) for k in ids]
This will use the order given by ids, not the order given by all_data.
Your second question isn't harder, just the proper way to structure your data from the beginning:
>>> all_data = {'abc': 123, 'cde': 234,'fgh': 345} # a dict
>>> ids = {'abc', 'fgh'} # a set
>>> {k:v for k,v in all_data.viewitems() if k in ids}
{'abc': 123, 'fgh': 345}
By the way, a nice fast way to get the matching keys is:
>>> all_data.viewkeys() & ids
set(['abc', 'fgh'])

Categories

Resources