This question already has answers here:
Loop "Forgets" to Remove Some Items [duplicate]
(10 answers)
Closed 8 years ago.
Define a function split_list that takes in a list of numbers and a number a and splits it into two sublists: list1 that contains numbers smaller than or equal to a, and another list, list2 containing numbers greater than a. list1 and list2 must be returned as elements of a tuple.
My code:
def split_list(lst, a):
list1 = []
list2 = []
for i in lst:
if i <= a:
list1.append(i)
lst.remove(i)
elif i > a:
list2.append(i)
lst.remove(i)
return (list1, list2)
Test code:
split_list([1, 10, 4, 9, 7, 2, 5, 8, 3, 4, 9, 6, 2], 5)
should give: ([1, 4, 2, 5, 3, 4, 2], [10, 9, 7, 8, 9, 6])
But I got ([1, 4, 5, 3, 2], [7, 9]) instead. Whats wrong with my code?
As commented by Martijn, you're breaking your list lst by trying to iterate through it and remove from it at the same time.
You don't need to remove from lst, so you can remove those lines.
Or, you could iterate over a copy of lst, whilst removing from the original lst.
To do this, simply change your for loop to be:
for i in lst[:]
This will copy a slice corresponding to the whole of lst for you to iterate over.
To avoid skipping elements you can alternatively loop through the list backwards deleting as you go. Here's an example using list indexes instead of the "for listitem in list" construct.
def split_list(lst, a):
list1 = []
list2 = []
for x in range(len(lst)-1,-1,-1):
if lst[x] <= a:
list1.append(lst[x])
del lst[x]
elif lst[x] > a:
list2.append(lst[x])
del lst[x]
return (list1, list2)
print split_list([1, 10, 4, 9, 7, 2, 5, 8, 3, 4, 9, 6, 2], 5)
# outputs ([2, 4, 3, 5, 2, 4, 1], [6, 9, 8, 7, 9, 10])
Modifying a list while iterating over it is always going to end badly. I would do instead:
for i in lst[:]: # Make a shallow copy.
#stuff
We are then iterating over that unmodified copy, so based on this we can edit the original safely.
Or just don't modify the list at all, meaning you can remove all uses of lst.remove(i) which should also fix the problem.
def split_list(lst, a):
list1 = []
list2 = []
for i in lst:
if i <= a:
list1.append(i)
elif i > a:
list2.append(i)
return (list1, list2)
There's no need to remove the items from the lst list as you iterate through it.
Related
I have an array list like this:
list = [1,2,3,4,9,1,12,9,8,7,8,9,10,12,16,1,2,3,4,5,6,7,8,9,10]
I want to create a sub-list from a list of ordered numbers (which are already in sequence in arr_list for e.g. 1,2,3,4 are already in order, similarly 7,8,9,10 and last 10 numbers)
Final output will look like this:
[[1,2,3,4],[7,8,9,10],[1,2,3,4,5,6,7,8,9,10]]
Tried comparing if the i'th element of first for loop is less than the j'th element of second for loop.
This is what i've tried:
sub_list=[]
for i in range(0,length_of_list):
for j in range(i+1,length_of_list):
if (arr_list[i] < arr_list[j]):
sub_list.append(arr_list[i])
else:
pass
New to python, any leads are much appreciated.
Try this...
res, temp = [], []
lst = [1,2,3,4,9,1,12,9,8,7,8,9,10,12,16,1,2,3,4,5,6,7,8,9,10]
for i in lst:
if (not temp) or (temp[-1] == i-1):
temp.append(i)
else:
res.append(temp)
temp = [i]
res.append(temp)
print([i for i in res if len(i)>1])
Outputs:
[[1, 2, 3, 4], [7, 8, 9, 10], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
tell me if its okay for you...
I have a list with a strange structure as follows:
List_input = [['statment01'], ['statment02'], ['statment03'],.....['statement1000']]
I need to remove the inner brackets [] and the single notations of each item.
The required output list is like this:
List_output = ["statment01", "statment02", "statment03",....., "statement1000"]
Could anyone help with this?
Just iterate over list and append it to new array.
List_output = []
for i in List_input:
List_output.append(i[0])
I hope this is what u r expecting:
def remove_nest(l):
for i in l:
if type(i) == list:
remove_nest(i)
else:
output.append(i)
l = [[1,2,3],[4,5,6],[6,7,8]]
output = []
print ('The given list: ', l)
remove_nest(l)
print ('The list after removing nesting: ', output)
OUTPUT:
The given list: [[1, 2, 3], [4, 5, 6], [6, 7, 8]]
The list after removing nesting: [1, 2, 3, 4, 5, 6, 6, 7, 8]
I would like to append to a new list all elements of an existing list of lists after a specific point
m = [[1,2,3],[4,5,10],[6,2,1]]
specific point = m[0][2]
newlist = [3,4,5,10,6,2,1]
You can directly slice off the remainder of the first target list and then add on all subsequent elements, eg:
m = [[1,2,3],[4,5,10],[6,2,1]]
y, x = 0, 2
new_list = m[y][x:] + [v for el in m[y+1:] for v in el]
# [3, 4, 5, 10, 6, 2, 1]
Here's a couple of functional approaches for efficiently iterating over your data.
If sublists are evenly sized, and you know the index from where to begin extracting elements, use chain + islice:
from itertools import chain, islice
n = 3 # Sublist size.
i,j = 0,2
newlist = list(islice(chain.from_iterable(m), i*n + j, None))
If you don't know the size of your sublists in advance, you can use next to discard the first portion of your data.
V = chain.from_iterable(m)
next(v for v in V if v == m[i][j])
newlist = list(V)
newlist.insert(m[i][j], 0)
This assumes there is no identical value earlier in the sequence.
You can put a conditional in your iteration and only add based on that condition. Once you hit that specific index, make your condition true. Something like this:
m = [[1,2,3],[4,5,10],[6,2,1]]
specific_point = (0,2)
newlist = [3,4,5,10,6,2,1]
output = []
for i in range(len(m)):
for j in range(len(m[i])):
if (i,j) < specific_point:
continue
output.append(m[i][j])
output:
[3, 4, 5, 10, 6, 2, 1]
why not flatten the initial list and go from there
flat_list = [item for sublist in m for item in sublist]
would return [1,2,3,4,5,10,6,2,1] so now you're really on flat_list[2:]
Most of the answers only work for this specific shape of nested list, but it's also possible to create a solution that works with any shape of nested list.
def flatten_from(sequence, path=[]):
start = path.pop(0) if path else 0
for item in sequence[start:]:
if isinstance(item, (list, tuple)):
yield from flatten_from(item, path)
else:
yield item
With the example from the question
>>> list(flatten_from([[1, 2, 3], [4, 5, 10], [6, 2, 1]], [0, 2]))
[3, 4, 5, 10, 6, 2, 1]
It also works with any shape and level of nesting of the input data
m = [[1], [[2], [3, 4, 5, 6, 7]], 8, [9, [10, 11]]]
flatten_from(m, [])) # 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
flatten_from(m, [2]) # 8, 9, 10, 11
flatten_from(m, [1, 1, 3]) # 6, 7, 8, 9, 10, 11
This is a bit of a bastard algorithm, though. On one hand, it uses nice functional programming concepts: recursion and yield.
On the other hand it relies on the side effect of mutating the path argument with list.pop, so it's not a pure function.
Below solution will work for your case where your array is restricted to list of list and the size of 'sublist' is consistent throughout i.e "3" in your case
m = [[1,2,3],[4,5,10],[6,2,1]] #input 2D array
a, b = 0, 2 #user input --> specific point a and b
flat_list_m = [item for firstlist in m for item in firstlist] #flat the 2D list
print (flat_list_m[len(m[0])*a+b:]) #print from specific position a and b, considering your sublist length is consistent throughout.
I hope this helps! :)
I am trying to reorder items in a list in a way illustrated by the following example:
Suppose the list before reordering is:
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I want to implement a method called reorder_list(list, custom_order) such that:
list1 = reorder_list(list1, [3, 6, 12, 9])
print(list1)
Out: [3, 6, 9, 1, 2, 4, 5, 7, 8, 10]
Explanation: [3, 6, 12, 9] is a custom order I am specifying. 12 is not in list1 so it will be ignored. 3,6,9 are in list1, so they get moved to the front of the list and their order is the same as in [3, 6, 12, 9]. The remaining items in list1 are after 3,6,9 and in the original order.
Is there is an easier way (and a Pythonic way) than implementing the C-like loop code. For my purpose I care more about code simplicity than performance.
def reorder_list(items, early):
moved = [item for item in early if item in items]
remain = [item for item in items if item not in moved]
return moved + remain
This is really the same algorithm as Gireesh and Stephen Rauch wrote. Gireesh's version is written as it would be before list comprehensions, while Stephen's uses sets for faster lookups (but converts both input lists to sets; one should suffice) and extends with a generator expression instead of allocating a second list.
One thing of note is that we've assumed items are unique within the lists. Both in and set expect this.
00sdf0's answer uses a very different algorithm that might make sense in Haskell, with its lazy evaluation and tail call optimization, but in this case seems neither easily understood nor performant. It can be more clearly rewritten using slices:
def reorder_list(items, early):
result = list(items)
for move in reversed(early):
try:
place = result.index(move)
result = [result[place]] + result[:place] + result[place+1:]
except ValueError:
pass # this item wasn't in the list
This does allocate more lists, effectively shallow copying the list twice per moved item. Using islice instead of slice produced lazy evaluation that avoided one of those copies.
def reorder_list(list_main, custom_order):
# initializing empty list
list1 = list()
# to add values of custom list to list1 which are present in main list
for value in custom_order:
# add only the values which are present in main list
if value in list_main:
list1.append(value)
# to add remaining element of main list to list1 which are not present in list1
for value in list_main:
if value not in list1:
list1.append(value)
return list1
list1 = [1,2,3,4,5,6,7,8,9,10]
list1 = reorder_list(list1, [3,6,12,9])
print(list1)
A couple of list comprehensions should be reasonably performant for this:
Code:
def reorder_list(list_to_reorder, custom_order):
new_list = [x for x in custom_order if x in set(list_to_reorder)]
new_list.extend(x for x in list_to_reorder if x not in set(custom_order))
return new_list
Test Code:
list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(reorder_list(list1, [9, 6, 3, 12]))
Results:
[9, 6, 3, 1, 2, 4, 5, 7, 8, 10]
The problem may be solved in the following way using itertools.chain and itertools.islice.
from itertools import chain, islice
lst = [1,2,3,4,5,6,7,8,9,10]
items_to_move = [9,6,3,12]
# move index i to front of list
def front(seq, i):
item = islice(seq, i, i+1)
start = islice(seq, 0, i, None)
end = islice(seq, i+1, None)
return list(chain(item,start,end))
for item in reversed(items_to_move):
if item in lst:
lst = front(lst, lst.index(item))
Output:
[9, 6, 3, 1, 2, 4, 5, 7, 8, 10]
I have a list like:
list = [[1,2,3],[4,5,6],[7,8,9]]
I want to append a number at the start of every value in the list programmatically, say the number is 9. I want the new list to be like:
list = [[9,1,2,3],[9,4,5,6],[9,7,8,9]]
How do I go about doing this in Python? I know it is a very trivial question but I couldn't find a way to get this done.
for sublist in thelist:
sublist.insert(0, 9)
don't use built-in names such as list for your own stuff, that's just a stupid accident in the making -- call YOUR stuff mylist or thelist or the like, not list.
Edit: as the OP aks how to insert > 1 item at the start of each sublist, let me point out that the most efficient way is by assignment of the multiple items to a slice of each sublist (most list mutators can be seen as readable alternatives to slice assignments;-), i.e.:
for sublist in thelist:
sublist[0:0] = 8, 9
sublist[0:0] is the empty slice at the start of sublist, and by assigning items to it you're inserting the items at that very spot.
>>> someList = [[1,2,3],[4,5,6],[7,8,9]]
>>> someList = [[9] + i for i in someList]
>>> someList
[[9, 1, 2, 3], [9, 4, 5, 6], [9, 7, 8, 9]]
(someList because list is already used by python)
Use the insert method, which modifies the list in place:
>>> numberlists = [[1,2,3],[4,5,6]]
>>> for numberlist in numberlists:
... numberlist.insert(0,9)
...
>>> numberlists
[[9, 1, 2, 3], [9, 4, 5, 6]]
or, more succintly
[numberlist.insert(0,9) for numberlist in numberlists]
or, differently, using list concatenation, which creates a new list
newnumberlists = [[9] + numberlist for numberlist in numberlists]
If you're going to be doing a lot of prepending,
perhaps consider using deques* instead of lists:
>>> mylist = [[1,2,3],[4,5,6],[7,8,9]]
>>> from collections import deque
>>> mydeque = deque()
>>> for li in mylist:
... mydeque.append(deque(li))
...
>>> mydeque
deque([deque([1, 2, 3]), deque([4, 5, 6]), deque([7, 8, 9])])
>>> for di in mydeque:
... di.appendleft(9)
...
>>> mydeque
deque([deque([9, 1, 2, 3]), deque([9, 4, 5, 6]), deque([9, 7, 8, 9])])
*Deques are a generalization of stacks and queues (the name is pronounced "deck" and is short for "double-ended queue"). Deques support thread-safe, memory-efficient appends and pops from either side of the deque with approximately the same O(1) performance in either direction.
And, as others have mercifully mentioned:
For the love of all things dull and ugly,
please do not name variables after your favorite data-structures.
#!/usr/bin/env python
def addNine(val):
val.insert(0,9)
return val
if __name__ == '__main__':
s = [[1,2,3],[4,5,6],[7,8,9]]
print map(addNine,s)
Output:
[[9, 1, 2, 3], [9, 4, 5, 6], [9, 7, 8, 9]]