Trim a list to a maximum number of elements [duplicate] - python

This question already has answers here:
How to force a list to a fixed size?
(7 answers)
Closed 3 years ago.
I would like to remove the oldest-added (i.e. the first) elements of a list, such that this list never exceeds 100 elements.
I thought about:
L = [327983, 232382, 1, 2, 3, 4, 5, 6, 23]
if len(L) > 100:
for i in range(len(L)-100):
del L[0]
print L # [4, 5, 6, 23]
Is there a solution without iteration (or more generally: a nicer solution) for trimming the beginning of the list, so that it has <= 100 elements?
Sidenote: Isn't there something else than lists, for this purpose? i.e. a data structure that has a maximum size, and such that if more data comes, the oldest are deleted! (It makes me think about FIFO? Stack? Pipe?)

How about using collection.deque? If you specify maxlen, it will not store more than maxlen elements.
>>> from collections import deque
>>> q = deque([1, 2, 3], maxlen=3)
>>> q
deque([1, 2, 3], maxlen=3)
>>> q.append(4)
>>> q
deque([2, 3, 4], maxlen=3)

You can just assign a slice back to your list
L = L[-100:]

Related

Sort a list from an index to another index [duplicate]

This question already has answers here:
Sort a part of a list in place
(3 answers)
Closed 3 years ago.
Suppose I have a list [2, 4, 1, 3, 5].
I want to sort the list just from index 1 to the end, which gives me [2, 1, 3, 4, 5]
How can I do it in Python?
(No extra spaces would be appreciated)
TL;DR:
Use sorted with a slicing assignment to keep the original list object without creating a new one:
l = [2, 4, 1, 3, 5]
l[1:] = sorted(l[1:])
print(l)
Output:
[2, 1, 3, 4, 5]
Longer Answer:
After the list is created, we will make a slicing assignment:
l[1:] =
Now you might be wondering what does [1:], it is slicing the list and starts from the second index, so the first index will be dropped. Python's indexing starts from zero, : means get everything after the index before, but if it was [1:3] it will only get values that are in between the indexes 1 and 3, let's say your list is:
l = [1, 2, 3, 4, 5]
If you use:
print(l[1:])
It will result in:
[2, 3, 4, 5]
And if you use:
print(l[1:3])
It will result in:
[2, 3]
About slicing, read more here if you want to.
And after slicing we have an equal sign =, that just simply changes what's before the = sign to what's after the = sign, so in this case, we use l[1:], and that gives [2, 3, 4, 5], it will change that to whatever is after the = sign.
If you use:
l[1:] = [100, 200, 300, 400]
print(l)
It will result in:
[1, 100, 200, 300, 400]
To learn more about it check out this.
After that, we got sorted, which is default builtin function, it simple sorts the list from small to big, let's say we have the below list:
l = [3, 2, 1, 4]
If you use:
print(sorted(l))
It will result in:
[1, 2, 3, 4]
To learn more about it check this.
After that we come back to our first topic about slicing, with l[1:], but from here you know that it isn't only used for assignments, you can apply functions to it and deal with it, like here we use sorted.
Maybe temporarily put something there that's smaller than the rest? Should be faster than the other solutions. And gets as close to your "No extra spaces" wish as you can get when using sort or sorted.
>>> tmp = l[0]
>>> l[0] = float('-inf')
>>> l.sort()
>>> l[0] = tmp
>>> l
[2, 1, 3, 4, 5]
Benchmarks
For the example list, 1,000,000 iterations (and mine of course preparing that special value only once):
sort_u10 0.8149 seconds
sort_chris 0.8569 seconds
sort_heap 0.7550 seconds
sort_heap2 0.5982 seconds # using -1 instead of -inf
For 50,000 lists like [int(x) for x in os.urandom(100)]:
sort_u10 0.4778 seconds
sort_chris 0.4786 seconds
sort_heap 0.8106 seconds
sort_heap2 0.4437 seconds # using -1 instead of -inf
Benchmark code:
import timeit, os
def sort_u10(l):
l[1:] = sorted(l[1:])
def sort_chris(l):
l = l[:1] + sorted(l[1:])
def sort_heap(l, smallest=float('-inf')):
tmp = l[0]
l[0] = smallest
l.sort()
l[0] = tmp
def sort_heap2(l):
tmp = l[0]
l[0] = -1
l.sort()
l[0] = tmp
for _ in range(3):
for sort in sort_u10, sort_chris, sort_heap, sort_heap2, sort_rev:
number, repeat = 1_000_000, 5
data = iter([[2, 4, 1, 3, 5] for _ in range(number * repeat)])
# number, repeat = 50_000, 5
# data = iter([[int(x) for x in os.urandom(100)] for _ in range(number * repeat)])
t = timeit.repeat(lambda: sort(next(data)), number=number, repeat=repeat)
print('%10s %.4f seconds' % (sort.__name__, min(t)))
print()
Use sorted with slicing:
l[:1] + sorted(l[1:])
Output:
[2, 1, 3, 4, 5]
For the special case that you actually have, according to our comments:
Q: I'm curious: Why do you want this? – Heap Overflow
A: I'm trying to make a next_permutation() in python – nwice13
Q: Do you really need to sort for that, though? Not just reverse? – Heap Overflow
A: Yup, reverse is ok, but I just curious to ask about sorting this way. – nwice13
I'd do that like this:
l[1:] = l[:0:-1]
You can define your own function in python using slicing and sorted and this function (your custom function) should take start and end index of the list.
Since list is mutable in python, I have written the function in such a way it doesn't modify the list passed. Feel free to modify the function. You can modify the list passed to this function to save memory if required.
def sortedList(li, start=0, end=None):
if end is None:
end = len(li)
fi = []
fi[:start] = li[:start]
fi[start:end] = sorted(li[start:end])
return fi
li = [2, 1, 4, 3, 0]
print(li)
print(sortedList(li, 1))
Output:
[2, 1, 4, 3, 0]
[2, 0, 1, 3, 4]

Is there a function to convert a int list to a list that shows the smallest-to-largest order of the list? [duplicate]

This question already has answers here:
Sorting list based on values from another list
(20 answers)
Closed 3 years ago.
I need a function that turns a list like
[10,5,2,3,7]
to a list like
[4,2,0,1,3]
Basically a list [0,1,2,3,4...] but arranged in the order that the original list has, smallest to biggest.
I have no idea where to even start on a function like this. I have Python 3.5.2.
hiro protagonist's answer was close, but he indexed the wrong list.
>>> data = [10,5,2,3,7]
>>> sorted_list = sorted(data)
>>> [sorted_list.index(item) for item in data]
[4, 2, 0, 1, 3]
This wouldn't account for cases where you want to account for multiple occurrences and whatnot, but I'm not sure if that's required in your case.
Try this:
>>> d = [10, 5, 2, 3, 7]
>>> [sorted(d).index(i) for i in d]
[4, 2, 0, 1, 3]
This solution would work; however, there is probably a solution that is more space efficient. This solution does allow for repeat elements though.
l1 = [10, 5, 2, 3, 7] # Your list
l2 = sorted(l1) # Get the sorted version of our list.
# A dictionary containing each element and a list of the indices where they are found
element_indices = {}
for index, element in enumerate(l2):
if element not in element_indices:
element_indices[element] = [index] # Store the index for each element when it is sorted
else: # We have seen this element before
element_indices[element].append(index)
l2 = [element_indices[value].pop() for value in l1] # Change each element to its sorted equivalent index
print(l2) # [4, 2, 0, 1, 3]

Dictionary from list [duplicate]

This question already has answers here:
Convert [key1,val1,key2,val2] to a dict?
(12 answers)
Closed 5 years ago.
How to create a dictionary from List when my list is like below
L1 = [1,2,3,4,5,6,7,8,9]
and I want the result as a dictionary like
d = {'1':[2,3], '4':[5,6], '7':[8,9]}
Is any idea, how to implement this?
L = [1,2,3,4,5,6,7,8,9]
n = 3
dict = {}
for i in range(0, len(L), n):
#this creates chunks of size n
sub_list = L[i:i+n]
dict[sub_list[0]] = sub_list[1:]
print(dict)
To get dictionary entries of size 2, choose n=3 in this example.
one-liner:
dict((L1[i*3], [L1[i*3+1], L1[i*3+2]]) for i in xrange(len(L1)/3))
Explanation:
xrange(len(L1)/3) returns a lazy range from 0 to 2: [0, 1, 2].
Further for each element i of a range it transforms to a tuple (k, [v1, v2]]). So the final range will be [(1, [2, 3]), (4, [5, 6]), (7, [8, 9])]. And finally we use a dict constructor from list of tuples where each element considered as a key-value pair.
Final result is {1: [2, 3], 4: [5, 6], 7: [8, 9]}. To convert keys from number to string we need to replace L1[i*3] to str(L1[i*3]).

Remove and return adjacent elements from a list [duplicate]

This question already has answers here:
Remove adjacent element in a list in python
(2 answers)
Closed 7 years ago.
I have a list like this: [1, 3, 4, 5, 1]
and I want to remove the first n elements, so for n = 3, I want to return that list, while removing it from the original list. So I'd have [1,3,4]
and my original list is now [5, 1].
What is the best way to do that in python?
In Python 2.7 this would look like the following. Simply extract a partial list and delete the unneeded part in the original version.
lst = [1, 3, 4, 5, 1]
new_lst = lst[:3]
del lst[:3]
print lst
print new_lst
If you want to mutate the original object, you can change it using [:]. For example:
>>> x = ['a','b','c','d','e']
>>> x[:], removed = x[3:], x[:3]
>>> x
['d', 'e']
>>> removed
['a', 'b', 'c']
This works because the terms on the right hand side, x[3:] and x[:3], are both evaluated before they're assigned to the targets on the left (x[:] and removed).
Something like this?
def pop_n(lst, n):
"""
Deletes the first *n* elements from *lst* and returns them.
"""
# validate inputs
# might want to use something other than isinstance()
if not isinstance(n, int) or n < 0:
raise ValueError("n must be a non-negative integer, not {}"
.format(n))
# store the elements to return
ret = lst[:n]
# remove the elements from the original list
del lst[:n]
return ret
EDIT: Here's a demonstration with your example case.
>>> x = [1, 3, 4, 5, 1]
>>> pop_n(x, 3)
[1, 3, 4]
>>> x
[5, 1]
>>> original = [1, 3, 4, 5, 1]
>>> removed, original[:3] = original[:3], ()
>>> removed, original
([1, 3, 4], [5, 1])

Find maximum with limited length in a list

I'm looking for maximum absolute value out of chunked list.
For example, the list is:
[1, 2, 4, 5, 4, 5, 6, 7, 2, 6, -9, 6, 4, 2, 7, 8]
I want to find the maximum with lookahead = 4. For this case, it will return me:
[5, 7, 9, 8]
How can I do simply in Python?
for d in data[::4]:
if count < LIMIT:
count = count + 1
if abs(d) > maximum_item:
maximum_item = abs(d)
else:
max_array.append(maximum_item)
if maximum_item > highest_line:
highest_line = maximum_item
maximum_item = 0
count = 1
I know I can use for loop to check this. But I'm sure there is an easier way in python.
Using standard Python:
[max(abs(x) for x in arr[i:i+4]) for i in range(0, len(arr), 4)]
This works also if the array cannot be evenly divided.
Map the list to abs(), then chunk the list and send it to max():
array = [1,2,4,5,4,5,6,7,2,6,-9,6,4,2,7,8]
array = [abs(item) for item in array]
# use linked question's answer to chunk
# array = [[1,2,4,5], [4,5,6,7], [2,6,9,6], [4,2,7,8]] # chunked abs()'ed list
values = [max(item) for item in array]
Result:
>>> values
[5, 7, 9, 8]
Another way, is to use islice method from itertools module:
>>> from itertools import islice
>>> [max(islice(map(abs,array),i,i+4)) for i in range(0,len(array),4)]
[5, 7, 9, 8]
To break it down:
1 - map(abs, array) returns a list of all absolute values of array elemets
2 - islice(map(abs,array),i,i+4)) slices the array in chunks of four elements
3 - i in range(0,len(array),4) stepping range for islice to avoid overlapping
This can be wrapped in function as fellows:
def max_of_chunks(lst, chunk_size):
lst = map(abs, lst)
result = [max(islice(lst,i,i+chunk_size)) for i in range(0,len(lst),chunk_size)]
return result
Upd: Oh, I've just seen newest comments to task and answers. I wasn't get task properly, my bad :) Let my old answer stay here for history. Max numbers from list chunks you can find in the way like that:
largest = [max(abs(x) for x in l[i:i+n]) for i in xrange(0, len(l), n)]
or
largest = [max(abs(x) for x in l[i:i+n]) for i in range(0, len(l), n)]
if you're use Python3.
Original answer just for history: If you had to choice some numbers (once) from not a big list, you shouldn't install big libraries like numpy for such simple tasks. There are a lot of techniques to do it with built-in Python tools. Here they are (something of them).
So we have some list and count of maximum different elements:
In [1]: l = [1, 2, 4, 5, 4, 5, 6, 7, 2, 6, -9, 6, 4, 2, 7, 8]
In [2]: n = 4
A. First we getting only unique numbers from source list by converting it to set. Then we creating a list consist of these unique numbers, sort it and finally get N last (greatest) elements:
In [3]: sorted(list(set(l)))[-n:]
Out[3]: [5, 6, 7, 8]
B. You can use built-in heapq module:
In [7]: import heapq
In [8]: heapq.nlargest(n, set(l))
Out[8]: [8, 7, 6, 5]
Of course you can 'wrap' A or B technique into some human-friendly function like def get_largest(seq, n): return sorted(list(set(l)))[-n:]. Yes I've ommited some details like handling IndexError. You should remember about it when you'll writing the code.
C. If your list(s) is very long and you had to do many of these operations so fast as Python can, you should use special third-party libraries like numpy or bottleneck.

Categories