Python Comprehensions - python

I've got a list of tuples, each tuple looks like (i,x).
i = index
x = value
I need to return a new list (using a comprehension only) that each value will be in the "right" index. If index is missing, we'll put the value -1000 to fill the gap.
For example:
Input: [(4,9), (0,2), (1,4), (3,2)]
Output should be: [2, 4, -1000, 2, 9]
I was trying to use index function, I'm trying to get the index of the tuple (1,2), while I "know" only the first element, the second can be anything.
I want to get the index of the tuple (1,2) by search (1,___), is that possible?
___ is a positive integer
return [sorted(L)[sorted(L).index((i,))][1] if i in [sorted(L)[j][0] for j in range(0,len(L))] else -1000 for i in range(sorted(L)[len(L)-1][0]+1)]
I can use list/dict/set comprehension, single line.
Thank you all for help!

With the help of a dictionary that maps indices to values, so we can easily and efficiently get the value for an index:
[g(i, -1000) for g in [dict(L).get] for i in range(max(L)[0] + 1)]
Try it online!

Related

Finding the sum of each level in a list with nested lists

I need to create a python function that takes a list of numbers (and possibly lists) and returns a list of both the nested level and the sum of that level. For example:
given a list [1,4,[3,[100]],3,2,[1,[101,1000],5],1,[7,9]] I need to count the values of all the integers at level 0 and sum them together, then count the integers at level 1 and sum them together, and so on, until I have found the sum of the deepest nested level.
The return output for the example list mentioned above should be:
[[0,11], [1,25], [2,1201]]
where the first value in each of the lists is the level, and the second value is the sum. I am supposed to use recursion or a while loop, without importing any modules.
My original idea was to create a loop that goes through the lists and finds any integers (ignoring nested lists), calculate the sum, then remove those integers from the list, turn the next highest level into integers, and repeat. However, I could not find a way to convert a list inside of a list into indivual integer values (essentially removing the 0th level and turning the 1st level into the new 0th level).
The code that I am working with now is as follows:
def sl(lst,p=0):
temp = []
lvl = 0
while lst:
if type(lst[0]) == int:
temp.append(lst[0])
lst = lst[1:]
return [lvl,sum(temp)]
elif type(lst[0]) == list:
lvl += 1
return [lvl,sl(lst[1:],p=0)]
Basically, I created a while loop to iterate through, find any integers, and append it to a temp list where I could then find the sum. But, I cannot find a way to make the loop access the next level to do the same, especially when the original list is going up and down in levels from left to right.
I would do it like this:
array = [1, 4, [3, [100]], 3, 2, [1, [101, 1000], 5], 1, [7, 9]]
sum_by_level = []
while array:
numbers = (element for element in array if not isinstance(element, list))
sum_by_level.append(sum(numbers))
array = [element for list_element in array if isinstance(list_element, list) for element in list_element]
print(sum_by_level)
print(list(enumerate(sum_by_level)))
Gives the output:
[11, 25, 1201]
[(0, 11), (1, 25), (2, 1201)]
So I sum up the non-list-elements and then take the list-elements and strip of the outer lists. I repeat this until the array is empty which means all levels where stripped off. I discarded to directly saving the level-information as it is just the index, but if you need that you can use enumerate for that (gives tuples though instead of lists).

Get indices of top N values from list in the order of the values

I have a list like a=[3,5,7,12,4,1,5] and need to get the indices of the top K(=3) elements of this list, in the order of the elements. So in this case, result should be
[3,2,1]
since top 3 elements are 12, 7, 5 (last one is tie so first index is returned).
What is the simplest way to get this?
As this is tagged numpy, you can use numpy.argsort on the opposite values (for reverse sorting), then slice to get the K desired values:
a = np.array([3,5,7,12,4,18,1,5,18])
K = 3
out = np.argsort(-a)[:K]
output: array([3, 2, 1])
If you want the indices in order of the original array but not necessarily sorted themselves in order of the values, you can also use numpy.argpartition:
out = np.argpartition(a, K)[-K:]
I assume you mean 3,2,1 right?
[a.index(i) for i in sorted(a)[:3:-1]]
Personally, I would create a sorted list through the sorted method, then compare the first K values with the .index attribute of a. This will yield you your desired result.
K = 3 #Number of elemens
a = [3,5,7,12,4,1,5]
a_sorted = sorted(a,reverse=True)
b = [a.index(v) for v in a_sorted[:K]]
print(b)
>>> [3, 2, 1]

Find minimum values of both "columns" of list of lists

Given a list like the next one:
foo_list = [[1,8],[2,7],[3,6]]
I've found in questions like Tuple pairs, finding minimum using python and
minimum of list of lists that the pair with the minimum value of a list of lists can be found using a generator like:
min(x for x in foo_list)
which returns
[1, 8]
But I was wondering if there is a similar way to return both minimum values of the "columns" of the list:
output = [1,6]
I know this can be achieved using numpy arrays:
output = np.min(np.array(foo_list), axis=0)
But I'm interested in finding such a way of doing so with generators (if possible).
Thanks in advance!
[min(l) for l in zip(*foo_list)]
returns [1, 6]
zip(*foo_list) gets the list transpose and then we find the minimum in both lists.
Thanks #mousetail for suggestion.
You can use two min() for this. Like -
min1 = min(a for a, _ in foo_list)
min2 = min(b for _, b in foo_list)
print([min1, min2])
Will this do? But I think if you don't want to use third party library, you can just use plain old loop which will be more efficient.

Enumerate list to make a new list of indices?

I'm trying to make a new list of indices by enumerated a previous list. Basically, what I want is:
To enumerate a list of elements to obtain indices for each element. I coded this:
board = ["O","O","O","O","O"]
for index,y in enumerate(board):
print(index,end=" ")
which gives:
0 1 2 3 4
I now want to make those numbers into a new list, but have no clue how to do that.
Thanks! Sorry for the question, I'm still a beginner and am just trying to get the hang of things.
You should probably just make a range of the right length:
board = ["O","O","O","O","O"]
indices = list(range(len(board)))
print(indices)
> [0, 1, 2, 3, 4]
Use list comprehension:
indices = [index for index, y in enumerate(board)]
If board is always a object, which implements the __len__-method, you can also use range:
indices = list(range(len(board)))
If you just want all the numbers you can use this:
indices = list(range(len(board)))
If you pass one number to range it will return an iterator with the numbers 0 up to the passed number (excluding). After this we turn it into a list with the list function.
You can use list comprehension to do that:
result = [index for index,y in enumerate(board)]
Alternatively you can use the range function:
result = range(len(board))
I would just use numpy arange, which creates an array that looks like the one you are looking for:
Numpy Arange
import numpy as np
enumerated = np.arange(len(board))
The straightforward way is:
board = ["O","O","O","O","O"]
newlist = []
for index,y in enumerate(board):
newlist.append(index)
A more advanced way using list comprehensions would be:
newlist = [index for index, value in enumerate(board)]

Populate a list in python

I have a series of Python tuples representing coordinates:
tuples = [(1,1), (0,1), (1,0), (0,0), (2,1)]
I want to create the following list:
l = []
for t in tuples:
l[ t[0] ][ t[1] ] = something
I get an IndexError: list index out of range.
My background is in PHP and I expected that in Python you can create lists that start with index > 0, i.e. make gaps and then fill them up, but it seems you can't.
The idea is to have the lists sorted afterwards. I know I can do this with a dictionary, but as far as I know dictionaries cannot be sorted by keys.
Update: I now know they can - see the accepted solution.
Edit:
What I want to do is to create a 2D array that will represent the matrix described with the tuple coordinates, then iterate it in order.
If I use a dictionary, i have no guarantee that iterating over the keys will be in order -> (0,0) (0,1) (0,2) (1,0) (1,1) (1,2) (2,0) (2,1) (2,2)
Can anyone help?
No, you cannot create list with gaps. But you can create a dictionary with tuple keys:
tuples = [(1,1), (0,1), (1,0), (0,0), (2,1)]
l = {}
for t in tuples:
l[t] = something
Update:
Try using NumPy, it provides wide range of operations over matrices and array. Cite from free pfd on NumPy available on the site (3.4.3 Flat Iterator indexing): "As mentioned previously, X.flat returns an iterator that will iterate over the entire array (in C-contiguous style with the last index varying the fastest". Looks like what you need.
You should look at dicts for something like that.
for t in tuples:
if not l.has_key(t[0]):
l[t[0]] = {}
l[t[0]][t[1]] = something
Iterating over the dict is a bit different than iterating over a list, though. You'll have the keys(), values() and items() functions to help with that.
EDIT: try something like this for ordering:
for x in sorted(l.keys()):
for y in sorted(l[x].keys()):
print l[x][y]
You create a one-dimensional list l and want to use it as a two-dimensional list.
Thats why you get an index error.
You have the following options:
create a map and use the tuple t as index:
l = {}
l[t] = something
and you will get entries in l as:
{(1, 1): something}
if you want a traditional array structure I'll advise you to look at numpy. With numpy you get n-dimensional arrays with "traditional" indexing.
As I mentioned use numpy,
with numpy you can create a 2-dimensional array, filled with zeros or ones or ...
Tha you can fill any desired value with indexing [x,y] as you desire.
Of course you can iterate over rows and columns or the whole array as a list.
If you know the size that you before hand,you can make a list of lists like this
>>> x = 3
>>> y = 3
>>> l = [[None] * x for i in range(y)]
>>> l
[[None, None, None], [None, None, None], [None, None, None]]
Which you can then iterate like you originally suggested.
What do you mean exactly by "but as far as I know dictionaries cannot be sorted by keys"?
While this is not strictly the same as a "sorted dictionary", you can easily turn a dictionary into a list, sorted by the key, which seems to be what you're after:
>>> tuples = [(1,1), (0,1), (1,0), (0,0), (2,1)]
>>> l = {}
>>> for t in tuples:
... l[t] = "something"
>>> sorted(l) # equivalent to sorted(l.keys())
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 1)]
>>> sorted(l.items()) # make a list of (key, value) tuples, and sort by key
[((0, 0), 'something'), ((0, 1), 'something'), ((1, 0), 'something'), ((1, 1), 'something'), ((2, 1), 'something')]
(I turned something into the string "something" just to make the code work)
To make use of this for your case however (if I understand it correctly, that is), you would still need to fill the dictionary with None values or something for every "empty" coordinate tuple)
Extending the Nathan's answer,
tuples = [(1,1), (0,1), (1,0), (0,0), (2,1)]
x = max(tuples, key = lambda z : z[0])[0] + 1
y = max(tuples, key = lambda z : z[1])[1] + 1
l = [[None] * y for i in range(x)]
And then you can do whatever you want
As mentioned earlier, you can't make lists with gaps, and dictionaries may be the better choice here. The trick is to makes sure that l[t[0]] exists when you put something in position t[1]. For this, I'd use a defaultdict.
import collections
tuples = [(1,1), (0,1), (1,0), (0,0), (2,1)]
l = collections.defaultdict(dict)
for t in tuples:
l[t[0]][t[1]] = something
Since l is a defaultdict, if l[t[0]] doesn't exist, it will create an empty dict for you to put your something in at position t[1].
Note: this ends up being the same as #unwesen's answer, without the minor tedium of hand-checking for existence of the inner dict. Chalk it up to concurrent answering.
The dict solutions given are probably best for most purposes. For your issue of iterating over the keys in order, generally you would instead iterate over the coordinate space, not the dict keys, exactly the same way you would have for your list of lists. Use .get and you can specify the default value to use for the blank cells, or alternatively use "collections.defaultdict" to define a default at dict creation time. eg.
for y in range(10):
for x in range(10):
value = mydict.get((x,y), some_default_value)
# or just "value = mydict[x,y]" if used defaultdict
If you do need an actual list of lists, you can construct it directly as below:
max_x, max_y = map(max, zip(*tuples))
l=[[something if (x,y) in tuples else 0 for y in range(max_y+1)]
for x in xrange(max_x+1)]
If the list of tuples is likely to be long, the for performance reasons, you may want to use a set for the lookup,as "(x,y) in tuples" performs a scan of the list, rather than a fast lookup by hash. ie, change the second line to:
tuple_set = set(tuples)
l=[[something if (x,y) in tuple_set else 0 for y in range(max_y+1)]
for x in xrange(max_x+1)]
I think you have only declared a one dimensional list.
I think you declare it as
l = [][]
Edit: That's a syntax error
>>> l = [][]
File "<stdin>", line 1
l = [][]
^
SyntaxError: invalid syntax
>>>

Categories

Resources