Relative size in list python - python

I have a list of integers. Each number can appear several times, the list is unordered.
I want to get the list of relative sizes. Meaning, if for example the original list is [2, 5, 7, 7, 3, 10] then the desired output is [0, 2, 3, 3, 1, 4]
Because 2 is the zero'th smallest number in the original list, 3 is one'th, etc.
Any clear easy way to do this?

Try a list comprehension with dictionary and also use set for getting unique values, like below:
>>> lst = [2, 5, 7, 7, 3, 10]
>>> newl = dict(zip(range(len(set(lst))), sorted(set(lst))))
>>> [newl[i] for i in lst]
[0, 2, 3, 3, 1, 4]
>>>
Or use index:
>>> lst = [2, 5, 7, 7, 3, 10]
>>> newl = sorted(set(lst))
>>> [newl.index(i) for i in lst]
[0, 2, 3, 3, 1, 4]
>>>

Related

How do I get the index of the common integer element from two separate lists and plug it to another list?

I have 3 lists.
A_set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Q_act = [2, 3]
dur = [0, 4, 5, 2, 1, 3, 4, 8, 2, 3]
All lists are integers.
What I am trying to do is to compare Q_act with A_set then obtain the indices of the numbers that match from A_set.
(Example:
Q_act has the elements [2,3]
it is located in indices [1,2] from A_set)
Afterwards, I will use those indices to obtain the corresponding value in dur and store this in a list called p_dur_Q_act.
(Example: using the result from the previous example, [1,2]
The values in the dur list corresponding to the indices [1,2] should be stored in another list called p_dur_Q_act
i.e. [4,5] should be the values stored in the list p_dur_Q_act)
So, how do I get the index of the common integer element (which is [1,2]) from two separate lists and plug it to another list?
So far here are the code(s) I used:
This one, I wrote because it returns the index. But not [4,5].
p_Q = set(Q_act).intersection(A_set)
p_dur_Q_act = [i + 1 for i, x in enumerate(p_Q)]
print(p_dur_Q_act)
I also tried this but I receive an error TypeError: argument of type 'int' is not iterable
p_dur_Q_act = [i + 1 for i, x in enumerate(Q_act) if any(elem in x for elem in A_set)]
print(p_dur_Q_act)
Another option is to use the enumerate iterator to generate every index, and then select only the ones you want:
a_set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
q_act = [2, 3]
dur = [0, 4, 5, 2, 1, 3, 4, 8, 2, 3]
p_dur_q_act = [i for i,v in enumerate(a_set) if v in q_act]
print([dur[p] for p in p_dur_q_act if p in dur]) # [4, 5]
This is more efficient than repeatedly calling index if the number of matches is large, because the number of calls is proportional to the number of matches, but the duration of calls is proportional to the length of a_set. The enumerate approach can be made even more efficient by turning q_act into a set, since in scales better with sets than lists. At these scales, though, there will be no observable difference.
You don't need to map these to index values, though. You can get the same result if you use zip to map a_set to dur and then select the d values whose a values are in q_act.
a_set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
q_act = {2, 3}
dur = [0, 4, 5, 2, 1, 3, 4, 8, 2, 3]
p_dur_q_act = [d for a, d in zip(a_set, dur) if a in q_act]
Use index function to get the index of the element in the list.
>>> a_set = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> q_act = [2, 3]
>>> dur = [0, 4, 5, 2, 1, 3, 4, 8, 2, 3]
>>>
>>> print([dur[a_set.index(q)] for q in set(a_set).intersection(q_act)])
[4, 5]

How can I find n smallest numbers without changing the order of the first list?

I intend to get the n smallest numbers in a list but keep the numbers in the same order they appear in the list. For example:
This is my list:
A = [1, 3, 4, 6, 7, 6, 8, 7, 2, 6, 8, 7, 0]
I like to get the first three lowest numbers as it has been ordered in the first list:
[1, 2, 0]
I do not want to sort the result as:
[0, 1, 2]
I have tried:
heapq.nsmallest(3,A)
but i wonder if it is possible to retain this list as:[1, 2, 0]
By the way, I'm not a Python coder so thanks for the help in advance.
You can try this:
new_a = []
A=[1, 3, 4, 6, 7, 6, 8, 7, 2, 6, 8, 7, 0]
for a in A:
if a not in new_a:
new_a.append(a)
new_a = [i for i in new_a if i in sorted(new_a)[:3]]
Output:
[1, 2, 0]
You could use heapq.nsmallest() to get the n smallest elements from the list. Then use collections.Counter to create a multiset from that list which you can use to check which elements from the original list to include in the result, e.g.
>>> from heapq import nsmallest
>>> from collections import Counter
>>> A = [1, 3, 4, 6, 7, 6, 8, 7, 2, 6, 8, 7, 0]
>>> n = 3
>>> c = Counter(nsmallest(n, A))
>>> result = []
>>> for elem in A:
... if c.get(elem, 0):
... result.append(elem)
... c[elem] -= 1
...
>>> result
[1, 2, 0]

Python list extend functionality using slices

I'm teaching myself Python ahead of starting a new job. Its a Django job, so I have to stick to 2.7. As such, I'm reading Beginning Python by Hetland and don't understand his example of using slices to replicate list.extend() functionality.
First, he shows the extend method by
a = [1, 2, 3]
b = [4, 5, 6]
a.extend(b)
produces [1, 2, 3, 4, 5, 6]
Next, he demonstrates extend by slicing via
a = [1, 2, 3]
b = [4, 5, 6]
a[len(a):] = b
which produces the exact same output as the first example.
How does this work? A has a length of 3, and the terminating slice index point is empty, signifying that it runs to the end of the list. How do the b values get added to a?
Python's slice-assignment syntax means "make this slice equal to this value, expanding or shrinking the list if necessary". To fully understand it you may want to try out some other slice values:
a = [1, 2, 3]
b = [4, 5, 6]
First, lets replace part of A with B:
a[1:2] = b
print(a) # prints [1, 4, 5, 6, 3]
Instead of replacing some values, you can add them by assigning to a zero-length slice:
a[1:1] = b
print(a) # prints [1, 4, 5, 6, 2, 3]
Any slice that is "out of bounds" instead simply addresses an empty area at one end of the list or the other (too large positive numbers will address the point just off the end while too large negative numbers will address the point just before the start):
a[200:300] = b
print(a) # prints [1, 2, 3, 4, 5, 6]
Your example code simply uses the most "accurate" out of bounds slice at the end of the list. I don't think that is code you'd use deliberately for extending, but it might be useful as an edge case that you don't need to handle with special logic.
It's simply an extension of normal indexing.
>>> L
[1, 2, 3, 4, 5]
>>> L[2] = 42
>>> L
[1, 2, 42, 4, 5]
The __setitem__() method detects that a slice is being used instead of a normal index and behaves appropriately.
a = [1, 2, 3]
b = [4, 5, 6]
a[len(a):] = b
means element in a from position len(a) are elements in b. Which means extending a with b.
For a demonstration, consider looking at a subclass of list:
from __future__ import print_function # so I can run on Py 3 and Py 2
class EdList(list):
def __setitem__(self,index,value):
print('setitem: index={}, value={}'.format(index,value))
list.__setitem__(self,index,value)
print(self)
def __setslice__(self,i,j,seq):
print('setslice: i:{}, j:{}, seq:{}'.format(i,j,seq))
self.__setitem__(slice(i,j),seq)
Running on Python 3:
>>> a=EdList(range(10))
>>> a[300000:]=[1,2,3]
setitem: index=slice(300000, None, None), value=[1, 2, 3]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
>>> a[1:1]=[4,5,6]
setitem: index=slice(1, 1, None), value=[4, 5, 6]
[0, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
Running on Python 2:
>>> a=EdList(range(10))
>>> a[300000:]=[1,2,3]
setslice: i:300000, j:9223372036854775807, seq:[1, 2, 3]
setitem: index=slice(300000, 9223372036854775807, None), value=[1, 2, 3]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
>>> a[1:1]=[4,5,6]
setslice: i:1, j:1, seq:[4, 5, 6]
setitem: index=slice(1, 1, None), value=[4, 5, 6]
[0, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]
It is confusing when you are first learning it, but you will learn to love it I think.

python sorting two lists

I am trying to sort two lists together:
list1 = [1, 2, 5, 4, 4, 3, 6]
list2 = [3, 2, 1, 2, 1, 7, 8]
list1, list2 = (list(x) for x in zip(*sorted(zip(list1, list2))))
Anyway, doing this gives me on output
list1 = [1, 2, 3, 4, 4, 5, 6]
list2 = [3, 2, 7, 1, 2, 1, 8]
while I would want to keep the initial order for equal number 4 in the first list: what I want is
list1 = [1, 2, 3, 4, 4, 5, 6]
list2 = [3, 2, 7, 2, 1, 1, 8]
What do I have to do? I wouldn't want to use loop for bubble-sorting. Any help appreciated.
Use a key parameter for your sort that only compares the first element of the pair. Since Python's sort is stable, this guarantees that the order of the second elements will remain the same when the first elements are equal.
>>> from operator import itemgetter
>>> [list(x) for x in zip(*sorted(zip(list1, list2), key=itemgetter(0)))]
[[1, 2, 3, 4, 4, 5, 6], [3, 2, 7, 2, 1, 1, 8]]
Which is equivalent to:
>>> [list(x) for x in zip(*sorted(zip(list1, list2), key=lambda pair: pair[0]))]
[[1, 2, 3, 4, 4, 5, 6], [3, 2, 7, 2, 1, 1, 8]]
The trick here is that when Python does tuple comparisons, it compares the elements in order from left to right (for example, (4, 1) < (4, 2), which is the reason that you don't get the ordering you want in your particular case). That means you need to pass in a key argument to the sorted function that tells it to only use the first element of the pair tuple as its sort expression, rather than the entire tuple.
This is guaranteed to retain the ordering you want because:
sorts are guaranteed to be stable. That means that when multiple records have the same key, their original order is preserved.
(source)
>>> list1 = [1, 2, 5, 4, 4, 3, 6]
>>> list2 = [3, 2, 1, 2, 1, 7, 8]
>>>
>>> list1, list2 = (list(x) for x in zip(*sorted(zip(list1, list2), key=lambda pair: pair[0])))
>>>
>>> print list1
[1, 2, 3, 4, 4, 5, 6]
>>> print list2
[3, 2, 7, 2, 1, 1, 8]
In you code the sorting is performed basing on the first and the second elements of the tuples, so the resulting second list elements are in the sorted order for the same elements of the first list.
To avoid sorting based on the second list, just specify that only the elements from the first list should be used in the comparison of the tuples:
>>> from operator import itemgetter
>>> list1, list2 = (list(x) for x in zip(*sorted(zip(list1, list2),key=itemgetter(0))))
>>> list1, list2
([1, 2, 3, 4, 4, 5, 6], [3, 2, 7, 2, 1, 1, 8])
itemgetter(0) takes the first element from each tuple, which belongs to the first list.

Access certain elements of a list

Can't figure out how to do this in a pretty way :
I have a list of n elements,
I want to access every m elements of the list.
For example : [1, 2, 3, 4, 5] and m = 2 would give
[2, 4]
I can do it simply with a loop, but ins't there a more "pythonic" way?
Thanks by advance !
EDIT :
Seems like I forgot something.
I want, not only get those values but modify them.
I tried slicing a[::2] = 3, but it doesn't work. . .
I'm searching for something similar
Slicing syntax does this for you:
>>> my_list = range(10)
>>> my_list
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> my_list[::2]
[0, 2, 4, 6, 8]
>>> my_list[1::2]
[1, 3, 5, 7, 9]
Here's a way to wrap a list to get the original assignment behavior you wanted, but I'm not sure I'd recommend it:
class AssignableSlice(list):
def __setitem__(self, i, v):
if isinstance(i, slice):
for ii in xrange(*i.indices(len(self))):
self[ii] = v
else:
super(AssignableSlice, self).__setitem__(i, v)
a = AssignableSlice(range(10))
print a
a[::2] = 3
print a
a[1::3] = 99
print a
produces:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[3, 1, 3, 3, 3, 5, 3, 7, 3, 9]
[3, 99, 3, 3, 99, 5, 3, 99, 3, 9]
Ned's answer shows how to use slices to access a portion of the list. You can also assign to a slice, but you need to assign a list to the slice, for example:
>>> my_list = range(5)
>>> my_list
[0, 1, 2, 3, 4]
>>> my_list[::2]
[0, 2, 4]
>>> my_list[::2] = [0, 0, 0]
>>> my_list
[0, 1, 0, 3, 0]
Note that when the step in your slice is anything besides the default of 1 the list that you assign needs to be the same length, however with a default step you can actually change the size of the list with slice assignment:
>>> my_list = range(5)
>>> my_list
[0, 1, 2, 3, 4]
>>> my_list[:1]
[0]
>>> my_list[:1] = [4, 3, 2] # replace the first item with 3 new items
>>> my_list
[4, 3, 2, 1, 2, 3, 4]
>>> my_list[2:5]
[2, 1, 2]
>>> my_list[2:5] = [] # remove the middle three items from the list
>>> my_list
[4, 3, 3, 4]
I juste found a way to do what I want using slicing.
The following :
candidates[::2] = [1] * len(candidates[::2])
will replace every 2 elements of candidates by 1

Categories