Trying to remove min and max values from two dimensional list in array.
My code:
myList = [[1, 3, 4], [2, 4, 4], [3, 4, 5]]
maxV = 0
minV = myList[0]0]
for list in myList:
for innerlist in list:
if innerlist > maxV:
maxV = innerlist
if innerlist < minV:
minV = innerlist
innerlist.remove(maxV)
innerlist.remove(minV)
print(myList)
This causes me some erros, which i not particulary understand. I'm quite sure that innerlist is not array but ordinary variable. But still i think it should be somehow possible to remove min and max elements from two dimensional list.
I mean I need to remove in every innerlist in my list highest and lowest values.
LF help!
Regards.
Just for the sake of showing a much simpler way of doing this using list comprehensions, the sorted method and slicing:
d = [[1, 3, 4], [2, 4, 4], [3, 4, 5]]
n = [sorted(l)[1:-1] for l in d]
print(n)
# [[3], [4], [4]]
Some reading material on each of the items used to solve this problem:
list
comprehension
sorted
slicing
To take care of duplicates, this answer by Padraic is very well done.
If you want to remove all occurrences, you will have to find the min and max and remove all occurrence from each sublist:
def remove(l):
for sub in l:
t = {min(sub), max(sub)}
sub[:] = (ele for ele in sub if ele not in t)
l = [[1, 3, 4], [1, 2, 4, 4], [3, 4, 5]]
remove(l)
Which will give you:
[[3], [2], [4]]
To find the min and max in a single pass you can use a helper function:
def min_max(sub):
# all numbers are > float("-inf") and < float("inf")
mx, mn = float("-inf"), float("inf")
for ele in sub:
if ele < mn:
mn = ele
if ele > mx:
mx = ele
return {mn, mx}
def remove(l):
for sub in l:
# find min and max
mn_mx = min_max(sub)
# update sublist so all occurrences of either are removed
sub[:] = (ele for ele in sub if ele not in mn_mx)
Even if your own logic worked and you wanted to remove all the elements equal to the max, it would not work using remove as it will only remove the first occurrence each time.
In [8]: l = [1,2,3,4,4]
In [9]: l.remove(4)
In [10]: l
Out[10]: [1, 2, 3, 4]
Based on one of your comments you seem to have strings in your sublists which will error when compared to an int, if the string is always the first element you can slice it off:
from itertools import islice
def remove(l):
for sub in l:
sub = sub[1:]
mn_mx = min_max(sub)
sub[:] = (ele for ele in sub if ele not in mn_mx)
try this approach:
foreach innerlist:
sort the array
remove the first element
remove the last element
It should work like this:
myList = [[1, 3, 4], [2, 4, 4], [3, 4, 5]]
for list in myList:
maxV = list[0] #initialise them here
minV = list[0] #because you look for max in list
for value in list:
if value> maxV:
maxV = innerlist
if value< minV:
minV = innerlist
list.remove(maxV) #remove from list
list.remove(minV)
print(myList)
Your errors where:
minV = myList[0]0] a [ to little
maxV = 0 works only if the list is always positive
maxV and minV should be inside the first loop
innerlist.remove(maxV) should be list.remove(maxV)
I also renamed innerList to value
Unindent your removes, to take them out of the loop and:
maxV = -10000000
minV = 10000000 # !!
Related
I have a list
arr=[1,-1,4,-1,4,2]
Is there a way to convert it to [[1],[4],[4,2]]?
Basically the -1 indicates where a sub-list ends
I tried
number_of_sublists=arr.count(-1)
lst=[[]]*(number_of_sublists+1)
idx=0
for i in arr:
print(idx)
if i==-1:
idx+=1
else:
lst[idx].append(i)
print(lst)
but it is giving me the output
[[1,4,4,2],[1,4,4,2],[1,4,4,2]]
Why is this happening
Try this:
arr=[1,-1,4,-1,4,2]
newarr = [[]]
for i in arr:
if i != -1:
newarr[-1].append(i)
else:
newarr.append([])
print(newarr)
Output:
[[1], [4], [4, 2]]
You can use itertols.groupby:
from itertools import groupby
arr = [1, -1, 4, -1, 4, 2]
[[*g] for k, g in groupby(arr, key=(-1).__ne__) if k]
# [[1], [4], [4, 2]]
All the answers provided work for your task, but if you want to know why your original code did not work, it is because how you are declaring the list lst.
lst=[[]]*(number_of_sublists+1)
By doing this, you are repeating the same list at each of the positions of lst, that is, yo have made number_of_sublists+1 references to the same list. So when you modify one of them, you are actually modifying all at the same time.
You could simply change the declaration to this and that would solve your problem:
lst = [[] for _ in range(number_of_sublists+1)]
try the below
arr = [1, -1, 4, -1, 4, 2]
result = [[]]
create_new_list = False
for x in arr:
if x == -1:
create_new_list = True
else:
if create_new_list:
result.append([])
create_new_list = False
result[-1].append(x)
print(result)
output
[[1], [4], [4, 2]]
I have:
l = [[1,2,3],[3,4],[1,6,8,3]]
I want:
[[1,2],[3,4],[1,6]]
Which is the list l with all sublists truncated to the lowest length found for the sublists in l.
I tried:
min = 1000
for x in l:
if len(x) < min: min = len(x)
r = []
for x in l:
s = []
for i in range(min):
s.append(x[i])
r.append(s.copy())
Which works but quite slow and long to write. I'd like to make this more efficient through list comprehension or similar.
Using del:
n = min(map(len, l))
for a in l:
del a[n:]
You can find the length of each item in the list and then pick min element from it. Later you can use this value to truncate all the items in the list
l = [[1,2,3],[3,4],[1,6,8,3]]
min_length = min(map(len,l)) # using map with len function to get the length of each item and then using min to find the min value.
l = [item[:min_length] for item in l] # list comprehension to truncate the list
One liner -
l = [item[:min(map(len,l))] for item in l]
One fun thing about zip is zip is the inverse itself, so list(zip(*zip(*x))) gives x in similar structure.
And zip stop iteration when any input is exhausted.
Though the results are tuples and the nested lists are not truncated in-place., one can make use of this to build the following output:
Output:
[(1, 2), (3, 4), (1, 6)]
l = [[1, 2, 3], [3, 4], [1, 6, 8, 3]]
print(list(zip(*zip(*l))))
With list comprehension, one-liner:
l = [[1,2,3],[3,4],[1,6,8,3]]
print ([[s[i] for i in range(min([len(x) for x in l]))] for s in l])
Or:
print ([s[:min([len(s) for s in l])] for s in l])
Output:
[[1, 2], [3, 4], [1, 6]]
We compute the minimal length of subslists in the 'range()' to iterate over sublists for that amount and to reconstruct a new subslist. The top-level list comprehension allows to reconstruct the nested sublist.
If you have a large nested list, you should use this version with two lines:
m = min([len(x) for x in l])
print ([[s[i] for i in range(m)] for s in l])
Or:
print ([s[:m] for s in l])
Using zip and preserving the list objects:
print (list([list(x) for x in zip(*zip(*l))]))
Output:
[[1, 2], [3, 4], [1, 6]]
I have a list of lists all of the same length. I would like to segment the first list into contiguous runs of a given value. I would then like to segment the remaining lists to match the segments generated from the first list.
For example:
Given value: 2
Given list of lists: [[0,0,2,2,2,1,1,1,2,3], [1,2,3,4,5,6,7,8,9,10], [1,1,1,1,1,1,1,1,1,1]
Return: [ [[2,2,2],[2]], [[3,4,5],[9]], [[1,1,1],[1]] ]
The closest I have gotten is to get the indices by:
>>> import itertools
>>> import operator
>>> x = 2
>>> L = [[0,0,2,2,2,1,1,1,2,3],[1,2,3,4,5,6,7,8,9,10],[1,1,1,1,1,1,1,1,1,1]]
>>> I = [[i for i,value in it] for key,it in itertools.groupby(enumerate(L[0]), key=operator.itemgetter(1)) if key == x]
>>> print I
[[2, 3, 4], [8]]
This code was modified from another question on this site.
I would like to find the most efficient way possible, since these lists may be very long.
EDIT:
Maybe if I place the lists one on top of each other it might be clearer:
[[0,0,[2,2,2],1,1,1,[2],3], -> [2,2,2],[2]
[1,2,[3,4,5],6,7,8,[9],10],-> [3,4,5],[9]
[1,1,[1,1,1],1,1,1,[1],1]] -> [1,1,1],[1]
You can use groupby to create a list of groups in the form of a tuple of starting index and length of the group, and use this list to extract the values from each sub-list:
from itertools import groupby
from operator import itemgetter
def match(L, x):
groups = [(next(g)[0], sum(1 for _ in g) + 1)
for k, g in groupby(enumerate(L[0]), key=itemgetter(1)) if k == x]
return [[lst[i: i + length] for i, length in groups] for lst in L]
so that:
match([[0,0,2,2,2,1,1,1,2,3], [1,2,3,4,5,6,7,8,9,10], [1,1,1,1,1,1,1,1,1,1]], 2)
returns:
[[[2, 2, 2], [2]], [[3, 4, 5], [9]], [[1, 1, 1], [1]]]
l=[[0,0,2,2,2,1,1,1,2,3], [1,2,3,4,5,6,7,8,9,10], [1,1,1,1,1,1,1,1,1,1]]
temp=l[0]
value=2
dict={}
k=-1
prev=-999
for i in range(0,len(temp)):
if(temp[i]==value):
if(prev!=-999 and prev==i-1):
if(k in dict):
dict[k].append(i)
else:
dict[k]=[i]
else:
k+=1
if(k in dict):
dict[k].append(i)
else:
dict[k]=[i]
prev=i
output=[]
for i in range(0,len(l)):
single=l[i]
final=[]
for keys in dict: #{0: [2, 3, 4], 1: [8]}
ans=[]
desired_indices=dict[keys]
for j in range(0,len(desired_indices)):
ans.append(single[desired_indices[j]])
final.append(ans)
output.append(final)
print(output) #[[[2, 2, 2], [2]], [[3, 4, 5], [9]], [[1, 1, 1], [1]]]
This seems to be one of the approach, this first creates the dictionary of contagious elements and then looks for that keys in every list and stores in output.
I'm pretty new in python and have am difficulty doing the next assignment.
I am receiving a list of lists with numbers and the word none, for example:
[[1,None],[2,4],[1.5,2]]
My problem is when I go through None (I need to sum up the lists) I need to replace it by the max number in the same place in the other lists.
So my result should be None = max(4,2) and receive :
[[1,4],[2,4],[1.5,2]]
If I go through a for loop I don't understand how can I go to the other sub lists and check them out (especially when I don't know how many subs lists I have)
Use a nested list comprehension with conditional
>>> l = [[1,None],[2,4],[1.5,2]]
>>> def findMax(j):
... return max(i[j] for i in l)
...
>>> [[j if j is not None else findMax(k) for k,j in enumerate(i)] for i in l]
[[1, 4], [2, 4], [1.5, 2]]
Here the list comprehension checks if each element is None or not. If not it will print the number, else it will fnd the maximum and print that element.
Another way using map is
>>> l = [[1,None],[2,4],[1.5,2]]
>>> maxVal = max(map(max, l))
>>> [[j if j is not None else maxVal for k,j in enumerate(i)] for i in l]
[[1, 4], [2, 4], [1.5, 2]]
Here is a hint: In Python, a for in loop iterates through all the elements in some iterable. If you have a list of lists, that means each element in the list can also have a for loop applied to it, as in a for loop inside a for loop. You could use this if and only if the maximum depth of a list is 2:
def get_deep_max(deeplst):
new = []
for elem in deeplst:
for num in elem:
new.append(num)
return max(new)
Try writing the code for replacing the none value yourself for practice.
Code:
for idx1, sublist in enumerate(list1):
for idx2, element in enumerate(sublist):
if element is None:
try:
sublist[idx2] = max(list1[idx1+1])
except IndexError:
pass
The problem is that if there is a None in the last list you didn’t specify what the code should do. I just added a try and except. You can replace pass with what you want the code to do.
My suggestion:
x = [[1,None],[2,4],[1.5,2]] #your list
highest_num = None # assume that 0 can be the highest number in a different situation
for each in x:`# find the highest number
for another in each:
if another > highest_num:
highest_num = another
for each in xrange(len(x)): # find the None and replace it with the highest number
for another in xrange(len(x[each])):
if x[each][another] is None:
x[each][another] = highest_num
from contextlib import suppress
l = [[1,None],[2,4],[1.5,2]]
for sub in l:
with suppress(ValueError):
i = sub.index(None) # find index of None in sublist (or ValueError)
sub[i] = max(s[i] for s in l if s[i] is not None) # replace sublist item with max of sublists in same index
break
print(l)
# [[1, 4], [2, 4], [1.5, 2]]
This one is a bit cleaner to read than the others IMO
l = [[1,None],[2,4],[1.5,2]]
maxVal = max(map(max, l)) # maps the function 'max' over all the sub-lists
for subl in l:
for idx,elem in enumerate(subl): # use enumerate to get the index and element
if elem is None:
subl[idx] = maxVal
print l
# [[1, 4], [2, 4], [1.5, 2]]
Here is my suggestion:
l = [[1, None], [2, 4], [1.5, 2]]
# l = [[1, None], [2, 4], [1.5, 2]]
l1 = zip(*l)
# l1 = [(1, 2, 1.5), (None, 4, 2)]
m = map(max, l1)
# m = [2, 4]
l2 = [map(lambda y: m[i] if y is None else y, x) for i,x in enumerate(l1)]
# l2 = [[1, 2, 1.5], [4, 4, 2]]
ret = zip(*l2)
# ret = [(1, 4), (2, 4), (1.5, 2)]
I'm trying to solve the Google's Python Basic Exercises and I tried solving this particular one about lists with list comprehension:
# D. Given a list of numbers, return a list where
# all adjacent == elements have been reduced to a single element,
# so [1, 2, 2, 3] returns [1, 2, 3]. You may create a new list or
# modify the passed in list.
def remove_adjacent(nums):
newList = []
newList = [i for i in nums if len(newList) == 0 or nums[i] != newList[-1]]
return newList
Obviously, output is not what I expected, and the author-made test function underlines this:
got: [2, 2, 3, 3, 3] expected [2, 3]
got: [1, 2, 2, 3] expected [1, 2, 3]
What's wrong with my function?
The problem with your code is that the newList you are referring to inside the list comprehension expression always stays the same empty list [] as you assigned it initially. The expression [i for i in nums if len(newList) == 0 or nums[i] != newList[-1]] is calculated first using the existing variable, and only then the result is assigned to newList.
In other words, your code is equivalent to
def remove_adjacent(nums):
newList = []
otherList = [i for i in nums if len(newList) == 0 or nums[i] != newList[-1]]
return otherList
You don't have to use list comprehension to solve this problem (and personally I wouldn't because it gets tricky in this case).
def adj(l):
if len(l) in {0,1}: # check for empty or list with 1 element
return l
return [ele for ind, ele in enumerate(l[:-1]) if ele != l[ind+1]] + [l[-1]]
if ele != l[ind+1]]checks the current element against the element at the next index in the list, we go to l[:-1] so l[ind+1] does not give an index error, because of this we need to add l[-1] the last element to the result.
In [44]: l = [1, 2, 2, 3]
In [45]: adj(l)
Out[45]: [1, 2, 3]
In [46]: l = [1, 2, 2, 3,2]
In [47]: adj(l)
Out[47]: [1, 2, 3, 2]
In [48]: l = [2,2,2,2,2]
In [49]: adj(l)
Out[49]: [2]
Using your own code you would need a for loop as newList is assigned to the list comprehension, you are not updating your original assignment of newList you have reassigned the name to the list comprehension which is a completely new object:
def remove_adjacent(nums):
if len(l) in {0,1}: # catch empty and single element list
return l
newList = [nums[0]] # add first element to avoid index error with `newList[-1]`
for i in nums[1:]: # start at second element and iterate over the element
if i != newList[-1]:
newList.append(i)
return newList
In [1]: l = [] # assign l to empty list
In [2]: id(l)
Out[2]: 140592635860536 # object id
In [3]: l = [x for x in range(2)] # reassign
In [4]: id(l)
Out[4]: 140592635862264 # new id new object