List Comprehension in Nested Lists - python

I have a list like [["foo", ["a", "b", "c"]], ["bar", ["a", "b", "f"]]]
and I'm wanting to split it out so I can get a count of the total number of As, Bs, etc. but I'm new to Python and having a bit of a time of it.
I'm using [lx for lx in [li[1] for li in fieldlist if li[1]]] to try and get a list with all of the items in the sub-sublists, but that returns a list with the first sublists ([["a", "b", "c"], ["a", "b", "f"]] instead of a list with the contents of those sublists. I'm pretty sure I'm just thinking about this wrong, since I'm new to list comprehensions and Python.
Anyone have a good way to do this? (and yes, I know the names I chose (lx, li) are horrible)
Thanks.

This will give you the list you want:
[lx for li in fieldlist for lx in li[1] if li[1]]

A Pythonic solution would be something like:
>>> from collections import Counter
>>> Counter(v for (field, values) in fieldlist
... for v in values)
Counter({'a': 2, 'b': 2, 'c': 1, 'f': 1})

List comprehension:
>>> s = [["foo", ["a", "b", "c"]], ["bar", ["a", "b", "f"]]]
>>> [x for y, z in s for x in z]
['a', 'b', 'c', 'a', 'b', 'f']
>>>
What is the purpose of your if li[1]? If li[1] is an empty list or other container, the test is redundant. Otherwise you should edit your question to explain what else it could be.

Related

How to write Dictionary from list with Duplicate Keys

Would like to convert list into dictionary, but here I have duplicate keys and it should not be considered in output_dict.
Following is input list and expected dictionary.
input_list = [[1,'a'],[1,'b'],[2,'c'],[2,'d']]
output_dict = {
1:['a','b'],
2:['c','d']
}
Wrote following programme and it gives desired result but somehow feel that it is not standard way of doing things in python. Any other way to write this ?
from pprint import pprint
output_dict = {}
list2 = []
input_list = [[1,'a'],[1,'b'],[2,'c'],[2,'d']]
keys = []
for i in input_list:
keys.append(i[0])
for key in keys:
list2 = []
for i in input_list:
if key in i:
list2.append(i[1])
output_dict[key] = list2
print("\n\n")
pprint(output_dict)
You can use collections.defaultdict or use dict.setdefault to have shorter code:
input_list = [[1, "a"], [1, "b"], [2, "c"], [2, "d"]]
out = {}
for k, v in input_list:
out.setdefault(k, []).append(v)
print(out)
Prints:
{1: ['a', 'b'], 2: ['c', 'd']}
I would suggest using set() to remove the duplicates from the list and then append it into a dictionary!
input_list = list(set(input_list))

how to keep count of each items in list - python [duplicate]

This question already has answers here:
How do I count the occurrences of a list item?
(29 answers)
Closed 10 months ago.
i was trying to keep count of each item in list in python and want to convert it into key-value pairs like json so i can able to iterate over it to present it on frontend using django.
list = ["a" , "a", "c", "b", "c", "d"]
here same i want this list into key value pairs with counting of each item in list
list = [{ "name":"a" , "count":2 } , { "name":"c" , "count":2 , ......}]
Use a set to count the number of each element in the list
l = ["a" , "a", "c", "b", "c", "d"]
d = {val: l.count(val) for val in set(l)}
this will give you :
{'c': 2, 'a': 2, 'b': 1, 'd': 1}
If you want to format the dict as you wrote it in your message (even though it's really inefficient), you can write it like that :
d = [{'name': val, 'count': l.count(val)} for val in set(l)}]
data = ["a" , "a", "c", "b", "c", "d"]
count_list=[{"name":d,"count": data.count(d)} for d in set(data)]
Probably the easiest way to do this:
def dict_count(list):
dict_tot = {}
for i in liste:
dict_tot[i] = liste.count(i)
print(dict_tot)

finding values in dictionary based on their key

I'm trying to find the values of keys based on their 3 first letters. I have three different categories of subjects that i have to get the grade from, stored as value with the subject being key. I have ECO, GEO, and INF. As there are multiple subjects i want to get the values from every key containing either ECO, GEO or INF.
subject={"INFO100":"A"}
(subject.get("INF"))
In this method i don't get the value, i have to use the whole Key. Is there a work-a-round? I want the values seperately so i can calculate their GPA based on their field of study:)
You need to iterate on the pairs, to filter on the key and keep the value
subject = {"INFO100": "A", "INF0200": "B", "ECO1": "C"}
grades_inf = [v for k, v in subject.items() if k.startswith("INF")]
print(grades_inf) # ['A', 'B']
grades_eco = [v for k, v in subject.items() if k.startswith("ECO")]
print(grades_eco) # ['C']
A said in the comments, the purpose of a dictionary is to have unique keys. Indexing is extremely fast as it uses hash tables. By searching for parts of the keys you need to loop and lose the benefit of hashing.
Why don't you store your data in a nested dictionary?
subject={'INF': {"INFO100":"A", "INFO200":"B"},
'OTH': {"OTHER100":"C", "OTHER200":"D"},
}
Then access:
# all subitems
subject['INF']
# given item
subject['INF']['INFO100']
For understanding porpoises, you can create a function that returns a dictionary, like:
def getGradesBySubject(dict, search_subject):
return [grade for subject,grade in dict.iteritems() if subject.startwith(search_subject)]
I'd suggest using a master dict object that contains a mapping of the three-letter subjects like ECO, GEO, to all subject values. For example:
subject = {"INFO100": "A",
"INFO200": "B",
"GEO100": "D",
"ECO101": "B",
"GEO003": "C",
"INFO101": "C"}
master_dict = {}
for k, v in subject.items():
master_dict.setdefault(k[:3], []).append(v)
print(master_dict)
# now you can access it like: master_dict['INF']
Output:
{'INF': ['A', 'B', 'C'], 'GEO': ['D', 'C'], 'ECO': ['B']}
If you want to eliminate duplicate grades for a subject, or just as an alternate approach, I'd also suggest a defaultdict:
from collections import defaultdict
subject = {"INFO100": "A",
"INFO300": "A",
"INFO200": "B",
"GEO100": "D",
"ECO101": "B",
"GEO003": "C",
"GEO102": "D",
"INFO101": "C"}
master_dict = defaultdict(set)
for k, v in subject.items():
master_dict[k[:3]].add(v)
print(master_dict)
defaultdict(<class 'set'>, {'INF': {'B', 'A', 'C'}, 'GEO': {'D', 'C'}, 'ECO': {'B'}})

How does this lambda function work exactly?

Can anybody explain to me please what exactly does this lambda function do?
from collections import Counter
def solve(a):
c = Counter(a)
return sorted(a, key=lambda k: (-c[k], k))
Thanks beforehand!
A lambda function is just like any other function, it's just expressed in a more compact way - so breaking it down:
lambda k : ( -c[k], k )
Is equivalent to:
def lambdafunction(k):
return (-c[k], k )
Where c is some in-scope variable - which per your solve function is a Counter.
The contents of that counter are keys and variables, and the lambda extracts those values and multiplies them by minus one, it then builds a tuple containing this extracted, negated value as the first entry, and the key as the second entry. These tuples are then used to perform the sort on the object to be solved, sorting the elements by frequency - most frequent first, with tie-breaking (i.e. where two or more elements share the same frequency) performed on the natural object.
e.g.
alist = ["a", "a", "b", "b", "b", "c", "c", "c", "c", "c", "c", "d", "d"]
solve(alist)
>> ['c', 'c', 'c', 'c', 'c', 'c', 'b', 'b', 'b', 'a', 'a', 'd', 'd']
Internally, there's a Counter which contains the values:
Counter({'a': 2, 'b': 3, 'c': 6, 'd': 2})
The lambda function converts these to tuples, which it associates with each element of the list before sorting them:
( -6, "c" )
( -3, "b" )
( -2, "a" )
( -2, "d" )
So all the "c" items appear at the top of the list, because the internally calculated tuples associated with them ( -6, "c" ) come first.
Using a lambda function like this within the sorted function gives sorted the flexibility to sort using whatever method you like - you define the function used to describe exactly what aspects of the collection you want sorted.
Counter(a) counts how many times each element is present in a, so this sorts a from most often element to least often element and when counts are the same it sorts alphabetically

Create a list of lists from a one-dimensional list, grouping each element by length

Let's say that I have a flat list:
flat_list = ["one", "a", "two", "b", "ab"]
My goal is to get a list of lists, each one containing every element with the same length, something like this:
list_lists = [["one", "two"], ["a", "b"], ["ab"]]
Is it possible to accomplish this with a simple list comprehension?
Use itertools.groupby to accomplish this (first we sort the list by length, using sorted, so that groupby works the way we want it to):
[list(group) for key, group in groupby(sorted(flat_list, key=len, reverse=True), len)]
>>> from itertools import groupby
>>> flat_list = ["one", "two", "a", "b", "ab"]
>>> list_of_lists = [list(group) for key, group in groupby(sorted(flat_list, key=len, reverse=True), len)]
>>>
>>> list_of_lists
[['one', 'two'], ['ab'], ['a', 'b']]
>>>
Here's my cut:
[[el for el in flat_list if len(el) == target_size + 1] for target_size in range(max([len(el) for el in flat_list]))]
Though I would prefer to split it into two lines:
max_len = max([len(el) for el in flat_list])
[[el for el in flat_list if len(el) == target_size + 1] for target_size in range(max_len )]
This will actually produce an empty list for any sizes lacking elements, so an input of flat_list = ["one", "two", "a", "b", "ab", 'eleven'] will produce
[['a', 'b'], ['ab'], ['one', 'two'], [], [], ['eleven']]
another "pure python"
flat_list = ["one", "two", "a", "b", "ab"]
d = {}
for w in flat_list:
d.update({len(w): d.setdefault(len(w), []) + [w]})
list(d.values())
Out[99]: [['one', 'two'], ['a', 'b'], ['ab']]
can be rewrtten as a list comp with some fancy footwork, still need an empty dict to start
d = {}
[list(d.values())
for w in flat_list + [''] if w == ''
or d.update({len(w): d.setdefault(len(w), []) + [w]})]
Python 3(will work with python 2 also) implementation without importing any libraries. Simple 4 liner
flat_list = ["one", "a", "two", "b", "ab"]
tmp_dict = dict()
for i in flat_list:
tmp_dict.setdefault(len(i), []).append(i)
list(tmp_dict.values()
Out[1]: [['one', 'two'], ['a', 'b'], ['ab']]

Categories

Resources