I realize that there's a lot of questions on here on the topic, however, I am unable to find one that helps me achieve a certain logic. I have the following list of lists:
unq_act = [[15, 'F7'],
[45, 'F7'],
[17, 'F7'],
[19, 'F7'],
[49, 'F7'],
[23, 'F7'],
[2, 'F7'],
[7, 'F7'],
[11, 'F3'],
[8, 'F7'],
[5, 'F7'],
[6, 'F3'],
[9, 'F7'],
[2, 'F7'],
[7, 'F7'],
[11, 'F3'],
[8, 'F7'],
[5, 'F7'],
[6, 'F3'],
[9, 'F7'],
[2, 'F7'],
[7, 'F7'],
[11, 'F3'],
[8, 'F7'],
[5, 'F7'],
[6, 'F3'],
[9, 'F7'],
[2, 'F7'],
[7, 'F7'],
[11, 'F3'],
[8, 'F7'],
[5, 'F7'],
[6, 'F3'],
[9, 'F7'],
[2, 'F7'],
[7, 'F7'],
[11, 'F3'],
[8, 'F7'],
[5, 'F7'],
[6, 'F3'],
[9, 'F7'],
[15, 'F17'],
[45, 'F17'],
[16, 'F7'],
[46, 'F7'],
[17, 'F7'],
[18, 'F7'],
[48, 'F7'],
[23, 'F7']]
The logic is that I want to:
1- Iterate over the list of lists. If the first element of a list reoccurs, check if the second element did NOT occur for the same first element(e.g. if 15 reoccurs, check if the second element did NOT reoccur).
2- If the above equates to true, I want to update the value by adding 30 to the first element.
For example:
For list [15, 'F7'], we check if the first element 15 reoccurs in the list which is true for list [15, 'F17']. We then check if the second elements are the same. Here, 'F7' is not equal to 'F17'. The , I want to add 30 to 15 making it 45.
This process is iterative, so then when checking for 45 using same condition it would update it to 75 and so on.
Essentially, this list would be converted to:
unq_act = [[15, 'F7'],
[45, 'F7'],
[17, 'F7'],
[19, 'F7'],
[49, 'F7'],
[23, 'F7'],
[2, 'F7'],
[7, 'F7'],
[11, 'F3'],
[8, 'F7'],
[5, 'F7'],
[6, 'F3'],
[9, 'F7'],
[2, 'F7'],
[7, 'F7'],
[11, 'F3'],
[8, 'F7'],
[5, 'F7'],
[6, 'F3'],
[9, 'F7'],
[2, 'F7'],
[7, 'F7'],
[11, 'F3'],
[8, 'F7'],
[5, 'F7'],
[6, 'F3'],
[9, 'F7'],
[2, 'F7'],
[7, 'F7'],
[11, 'F3'],
[8, 'F7'],
[5, 'F7'],
[6, 'F3'],
[9, 'F7'],
[2, 'F7'],
[7, 'F7'],
[11, 'F3'],
[8, 'F7'],
[5, 'F7'],
[6, 'F3'],
[9, 'F7'],
[75, 'F17'],
[105, 'F17'],
[16, 'F7'],
[46, 'F7'],
[17, 'F7'],
[18, 'F7'],
[48, 'F7'],
[23, 'F7']]
See lists that have elements 15 and 45 at the beginning of the list and how they were transformed.
Here is the code I tried which isn't updating anything in the list:
for i in unq_act:
for j in unq_act:
if i[0] == j[0] and i[1] != j[1]:
unq_act[unq_act.index(j)][0] == unq_act[unq_act.index(j)][0] + 30
print(unq_act[unq_act.index(j)][0])
Any help is appreciated.
If I understand the question properly, you want each number to correspond to exactly one string. If a second string is found, the number should be incremented by 30 until it either the string matches a previously found string for the new number, or until the number is unique.
For example, [[1, "F1"], [1, "F1"], [1, "F2"]] should have the last element turned into [31, "F2"].
This should be pretty easy to solve using a dictionary mapping from number to string:
mapping = {}
for inner in list_of_lists:
n, f = inner # unpack the list for convenience
while n in mapping and mapping[n] != f: # update the number if necessary
n += 30
inner[0] = n
if n not in mapping: # add unique numbers to the mapping
mapping[n] = f
s = set()
for l in unq_act:
sl = frozenset(l)
if sl in s:
l[0] += 30
else:
s.add(sl)
if it's possible for more than 1 equale sublists
s = set()
for l in unq_act:
sl = frozenset(l)
while True:
if sl in s:
l[0]+=30
sl = frozenset(l)
else:
s.add(sl)
break
Related
I have the following list, let's call it R:
[(array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]),
array([100, 101, 102])),
(array([[10, 11, 12],
[13, 14, 15],
[16, 17, 18]]),
array([103, 104, 105]))]
I want to be able to delete columns of R in a for loop, based on an index i. For example, if i = 3, the 3rd column should be deleted, which should result in the following new, say R1:
[(array([[1, 2],
[4, 5],
[7, 8]]),
array([100, 101])),
(array([[10, 11],
[13, 14],
[16, 17]]),
array([103, 104]))]
I have zero experience with handling such multi dimensional arrays, so I am unsure how to use numpy.delete(). My actual list R is pretty big, so I would appreciate if someone can suggest how to go about the loop.
You can use np.delete with col==2 and axis=-1.
# if your 'list' be like below as you say in the question :
print(lst)
# [
# array([[1, 2, 3],
# [4, 5, 6],
# [7, 8, 9]]),
# array([100, 101, 102]),
# array([[10, 11, 12],
# [13, 14, 15],
# [16, 17, 18]]),
# array([103, 104, 105])
# ]
for idx, l in enumerate(lst):
lst[idx] = np.delete(l, 2, axis=-1)
print(lst)
Output:
[
array([[1, 2],
[4, 5],
[7, 8]]),
array([100, 101]),
array([[10, 11],
[13, 14],
[16, 17]]),
array([103, 104])
]
Creating input array like in the question:
import numpy as np
lst = [[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]],
[100, 101, 102],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[103, 104, 105]
]
lst = [np.array(l) for l in lst]
Update base comment, If you have a tuple of np.array in your list, you can try like below:
lst = [
(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]), np.array([100, 101, 102])),
(np.array([[10, 11, 12], [13, 14, 15], [16, 17, 18]]), np.array([103, 104, 105]))
]
for idx, tpl in enumerate(lst):
lst[idx] = tuple(np.delete(l, 2, axis=-1) for l in tpl)
print(lst)
Output:
[
(array([[1, 2],
[4, 5],
[7, 8]]),
array([100, 101])
),
(array([[10, 11],
[13, 14],
[16, 17]]),
array([103, 104]))
]
I have an array of three dimension
x[i,j,k]=[[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]], [[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]], [[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]], [[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]]
And I need cumulative sum like the following
y[i][j][k]=[[[1, 21], [3, 28], [6, 36], [10, 45], [15, 55]], [1, 21], [3, 28], [6, 36], [10, 45], [15, 55]], [1, 21], [3, 28], [6, 36], [10, 45], [15, 55]], [1, 21], [3, 28], [6, 36], [10, 45], [15, 55]]]]
I have tried
for k in range(0,1):
for j in range(0,5):
for i in range(0,4):
y[i][j][k]=sum(sum(x[i][j][k] for jj in range(0,5) if jj<=j)for kk in range(0,1) if kk<=k)
but I got
y[i][j][k]=[[[1, 12], [3, 26], [6, 42], [10, 60], [15, 80]], [[1, 12], [3, 26], [6, 42], [10, 60], [15, 80]], [[1, 12], [3, 26], [6, 42], [10, 60], [15, 80]], [[1, 12], [3, 26], [6, 42], [10, 60], [15, 80]]]
How to do for loop as per my need?
I have
x[0][0][0]=1
x[0][1][0]=2
x[0][2][0]=3
x[0][3][0]=4
x[0][4][0]=5
x[0][0][1]=6
x[0][1][1]=7
x[0][2][1]=8
x[0][3][1]=9
x[0][4][1]=10
I need to do
y[0][0][0]=x[0][0][0]=1
y[0][1][0]=x[0][0][0]+x[0][1][0]=3
y[0][2][0]=x[0][0][0]+x[0][1][0]+x[0][2][0]=6
y[0][3][0]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]=10
y[0][4][0]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]=15
y[0][0][1]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]+x[0][0][1]=21
y[0][1][1]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]+x[0][0][1]+x[0][1][1]=28
y[0][2][1]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]+x[0][0][1]+x[0][1][1]+x[0][2][1]=36
y[0][3][1]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]+x[0][0][1]+x[0][1][1]+x[0][2][1]+x[0][3][1]=45
y[0][4][1]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]+x[0][0][1]+x[0][1][1]+x[0][2][1]+x[0][3][1]+x[0][4][1]=55
You can do the following, using some transpositioning trickery:
from itertools import accumulate, chain
result = []
for l in x:
a = [*accumulate(chain(*zip(*l)))] # [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]
result.append([*map(list, zip(a[:len(l)], a[len(l):]))])
[[[1, 21], [3, 28], [6, 36], [10, 45], [15, 55]],
[[1, 21], [3, 28], [6, 36], [10, 45], [15, 55]],
[[1, 21], [3, 28], [6, 36], [10, 45], [15, 55]],
[[1, 21], [3, 28], [6, 36], [10, 45], [15, 55]]]
I have an array of three dimension
x=
[[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]],
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]],
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]],
[[1, 6], [2, 7], [3, 8], [4, 9], [5, 10]]]
And I need cumulative sum like the following
y=
[[[1, 21], [3, 28], [6, 36], [10, 45], [15, 55]],
[[1, 21], [3, 28], [6, 36], [10, 45], [15, 55]],
[[1, 21], [3, 28], [6, 36], [10, 45], [15, 55]],
[[1, 21], [3, 28], [6, 36], [10, 45], [15, 55]]]
And I want to achieve this by using for loop and sum alone, i.e. without using any specific functions like in numpy or itertools, nor any extra temp variables.
I have tried
for k in range(0,1):
for j in range(0,5):
for i in range(0,4):
y[i][j][k]=sum(sum(x[i][j][k] for jj in range(0,5) if jj<=j)for kk in range(0,1) if kk<=k)
but I got
y[i][j][k]=[[[1, 12], [3, 26], [6, 42], [10, 60], [15, 80]],
[[1, 12], [3, 26], [6, 42], [10, 60], [15, 80]],
[[1, 12], [3, 26], [6, 42], [10, 60], [15, 80]],
[[1, 12], [3, 26], [6, 42], [10, 60], [15, 80]]]
How to do for loop as per my need?
I have
x[0][0][0]=1
x[0][1][0]=2
x[0][2][0]=3
x[0][3][0]=4
x[0][4][0]=5
x[0][0][1]=6
x[0][1][1]=7
x[0][2][1]=8
x[0][3][1]=9
x[0][4][1]=10
.
.
.
.
I need to do
y[0][0][0]=x[0][0][0]=1
y[0][1][0]=x[0][0][0]+x[0][1][0]=3
y[0][2][0]=x[0][0][0]+x[0][1][0]+x[0][2][0]=6
y[0][3][0]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]=10
y[0][4][0]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]=15
y[0][0][1]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]+x[0][0][1]=21
y[0][1][1]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]+x[0][0][1]+x[0][1][1]=28
y[0][2][1]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]+x[0][0][1]+x[0][1][1]+x[0][2][1]=36
y[0][3][1]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]+x[0][0][1]+x[0][1][1]+x[0][2][1]+x[0][3][1]=45
y[0][4][1]=x[0][0][0]+x[0][1][0]+x[0][2][0]+x[0][3][0]+x[0][4][0]+x[0][0][1]+x[0][1][1]+x[0][2][1]+x[0][3][1]+x[0][4][1]=55
.
.
.
(Reposting my question with my exact requirements clearly)
I believe the usual cumsum functions would put 1, not 21, in y[0][0][1] etc.
This code would do so:
y=[[[0,0] for b in range(5)] for a in range(4)]
for a in range(4):
for c in range(2):
cum = 0
for b in range(5):
cum+=x[a][b][c]
y[a][b][c] = cum
But if you want to get 21 simply move the cum = 0 line outside the c loop
EDIT
To avoid the extra variable:
for a in range(4):
for c in range(2):
y[a][0][c] = x[a][0][c]
for b in range(1,5):
y[a][b][c] = x[a][b][c] + y[a][b-1][c]
2nd EDIT
And to get 21 instead of 1 as the second value of the first pair:
for a in range(4):
for c in range(2):
y[a][0][c] = x[a][0][c]
if c==1:
y[a][0][1] += y[a][4][0]
for b in range(1,5):
y[a][b][c] = x[a][b][c] + y[a][b-1][c]
This should work:
y = [[[0, 0] for _ in range(len(x[0]))] for _ in range(len(x))]
for lst, ylst in zip(x, y):
for i, pair in enumerate(lst):
ylst[i][0] = sum(a for a, _ in lst[:i+1])
ylst[i][1] = sum(a for a, _ in lst) + sum(a for _, a in lst[:i+1])
You can achieve a processing of both cells in each sublist in a single iteration, using some modulo and floor division trickery:
# just a readablity helper to get values from nested list by running index
byi = lambda lst, i: lst[i%len(lst)][i//len(lst)] if i >= 0 else 0
y = [[[0, 0] for _ in range(len(x[0]))] for _ in range(len(x))]
for lst, ylst in zip(x, y):
for i in range(2 * len(lst)): # processes all 10 cells equally
ylst[i%len(lst)][i//len(lst)] = byi(lst, i) + byi(ylst, i-1)
I have a list that contains a lot of sublists, which are initially pairs of numbers, so it looks like:
list = [[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]
and what I want is to compare last digit of sublist with first digit in next sublist and if they match - merge them in one sublist. So output for two matching sublists would be something like that:
output = [[7, 8, 9]]
And, of course, if there is a row of matching sublists then to merge them all in one big sublist.
output = [[14, 15, 16, 17, 18, 19]]
I was thinking about using itemgetter as a kind of a key to compare. So probably something like:
prev_digit = itemgetter(-1)
next_digit = itemgetter(0)
but then initially I realised that I don't really understand how can I use it in Python, due to lack of knowledge. I tried to think of a for loop, but it didn't work out as I didn't know how to implement those "keys".
For some kind of inspiration I used this Python, comparison sublists and making a list but even with that I still have no solution.
Also, as my list can get kinda big (from human perspective, so like thousand pairs or stuff) I'm very interested in the most efficient way to do this.
And yes, I'm new to Python, so I would be very grateful for good explanation. Of course I can google, so you can avoid explaining functions in depth, but like general logic would be nice.
I think I wrote this once. It can be done with a single pass over the list.
alist = [[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]
l = [alist[0][:]]
for e in alist[1:]:
if l[-1][-1] == e[0]:
l[-1].append(e[1])
else:
l.append(e[:])
The code reads as start with the first pair. Loop over the rest. Check if the last element of the last list is the same as the first element of the pair. If so append the second element else append the pair to the list.
This results in l being:
[[2, 3], [4, 5], [7, 8, 9], [11, 12], [14, 15, 16, 17, 18, 19], [20, 21]]
If you only want the largest sublist I suggest:
>>> l = [[2, 3], [4, 5], [7, 8, 9], [11, 12], [14, 15, 16, 17, 18, 19], [20, 21]]
>>> max(l, key=len)
[14, 15, 16, 17, 18, 19]
And evaluated:
>>> alist = [[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]
>>>
>>> l = [alist[0][:]]
>>> for e in alist[1:]:
... if l[-1][-1] == e[0]:
... l[-1].append(e[1])
... else:
... l.append(e[:])
...
>>> l
[[2, 3], [4, 5], [7, 8, 9], [11, 12], [14, 15, 16, 17, 18, 19], [20, 21]]
>>> alist
[[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]
And compared. The reduce solution takes 6.4 usecs:
$ python -mtimeit "list = [[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]" "reduce(lambda x,y: x[:-1] + [x[-1] + y[1:]] if x[-1][-1] == y[0] else x + [y], list[1:], [list[0]])"
100000 loops, best of 3: 6.4 usec per loop
The for loop takes 3.62 usecs:
$ python -mtimeit "alist = [[2, 3], [4, 5], [7, 8], [8, 9], [11, 12], [14, 15], [15, 16], [16, 17], [17, 18], [18, 19], [20, 21]]" "l = [alist[0][:]]" "for e in alist[1:]:" " if l[-1][-1] == e[0]:" " l[-1].append(e[1])" " else:" " l.append(e[:])"
100000 loops, best of 3: 3.62 usec per loop
On Python 2.7.3. The for loop is 56% faster. The difference would likely be more pronounced with larger inputs as the cost of a list concatenation depends on the sum of the length of the two lists. Whereas appending to a list is slightly cheaper.
using reduce
>>> reduce(
... lambda x,y: x[:-1] + [x[-1] + y[1:]] if x[-1][-1] == y[0] else x + [y],
... list[1:],
... [list[0]]
... )
[[2, 3], [4, 5], [7, 8, 9], [11, 12], [14, 15, 16, 17, 18, 19], [20, 21]]
Explanation
Here is the lamdba function in expanded form used with reduce.
def mergeOverlappingRange(x, y):
if x[-1][-1] == y[0]:
return x[:-1] + [x[-1] + y[1:]]
else:
return x + [y]
reduce(mergeOverlappingRange, list[1:], [list[0]])
I want to make a new list of lists when the value in the 3rd column is of the highest 10%.
My list of lists currently look like this:
[[1, -1, 10, 0]]
[[2, 1, 20, 5]]
[[3, 2, 15, 10], [4, 2, 85, 10], [5, 2, 90, 10]]
[[6, 3, 75, 11], [7, 4, 78, 11], [8, 5, 80, 11]]
[[9, 6, 13, 14]]
[[10, 7, 50, 17]]
[[11, 8, 70, 30], [12, 8, 95, 30], [13, 8, 90, 30]].....
I was thinking of something along the lines of:
M1 = max(row1)[2] (maximum value from the 3rd column)
if row1[i][2] >= M1*(0.1):
newrow1.append()
Any help would be greatly appreciated!! Thanks in advance
You can use list comprehension:
[item for item in l if item[2]>10]