Let's say I'm not allowed to use libraries.
How do I go about calculating the product of indexes in a list.
Let's assume none of the integers are 0 or less.
The problem gets harder as I'm trying to calculate the indexes vertically.
bigList = [[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]
With numpy the solution for my problem would be:
import numpy as np
print([np.prod(l) for l in zip(*bigList)])
[1, 32, 243, 1024, 3125]
However without it my solution is much more chaotic:
rotateY = [l for l in zip(*bigList)]
productList = [1]* len(bigList)
count = 0
for l in rotateY:
for i in l:
productList[count] *= i
count += 1
print(productList)
[1, 32, 243, 1024, 3125]
You can iterate over each row getting each row's n-th element, and multiplying each element together:
>>> from functools import reduce
>>>
>>> def mul_lst(lst):
return reduce(lambda x, y: x * y, lst)
>>>
>>> bigList = [[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5],
[1, 2, 3, 4, 5]]
>>>
>>> [mul_lst([row[i] for row in bigList]) for i in range(len(bigList))]
[1, 32, 243, 1024, 3125]
If you cannot use any libraries, including functools, you can write the logic for the mul_lst function manually:
>>> def mul_lst(lst):
product = lst[0]
for el in lst[1:]:
product *= el
return product
>>> mul_lst([3, 3])
9
>>> mul_lst([2, 2, 2, 2, 2])
32
And why not simply:
productList = []
for i in range(len(bigList[0]):
p = 1
for row in bigList:
p *= row[i]
productList.append(p)
Alternatively, a small improvement over your solution:
productList = [1]* len(bigList[0])
for row in bigList:
for i, c in enumerate(row):
productList[i] *= c
We can transpose the nested list and then use reduce (a Python built-in) in Python 2.x on each element (list) for a one-liner -
>>> [reduce(lambda a,b: a*b, i) for i in map(list, zip(*bigList))]
[1, 32, 243, 1024, 3125]
Here's a quick recursive solution
def prod(x):
""" Recursive approach with behavior of np.prod over axis 0 """
if len(x) is 1:
return x
for i, a_ in enumerate(x.pop()):
x[0][i] *= a_
return prod(x)
Related
I have an array, let's say arr = [1, 2, 3, 4, 5, 6, 7, 8]
and another indices array: idx = [0, 3, 4, 6]
and I want to get two arrays, one is only those indices from arr: [1, 4, 5, 7]
and another one is all the rest: [2, 3, 6, 8]
Can someone help me with that? I can only think of ugly ways to do it, but it must be some function that does it elegantly.
Thanks a lot!
You could do it like this:
selected = [arr[i] for i in idx]
other = [v for i, v in enumerate(arr) if i not in idx]
If arr has no duplicates, you could also do:
other = [v for v in arr if v not in selected]
Way to do it:
a1 = [arr[x] for x in idx]
a2 = [x for x in arr if x not in a1]
With one traversal:
no, yes = both = [], []
for i, x in enumerate(arr):
both[i in idx].append(x)
Or (as commented by Chris_Rands):
yes, no = [], []
for i, x in enumerate(arr):
(yes if i in idx else no).append(x)
Though idx should either be small for this or turned into a set (same goes for the solutions in the other answers, I guess they just don't want to talk about it).
Demo:
>>> if 1:
arr = [1, 2, 3, 4, 5, 6, 7, 8]
idx = [0, 3, 4, 6]
no, yes = both = [], []
for i, x in enumerate(arr):
both[i in idx].append(x)
print('yes', yes)
print('no', no)
yes [1, 4, 5, 7]
no [2, 3, 6, 8]
There is a neat solution with numpy:
import numpy as np
arr = np.asarray([1, 2, 3, 4, 5, 6, 7, 8]) # converts your list in numpy array
idx1 = [0, 3, 4, 6]
idx2 = [1, 2, 5, 7]
arr1 = arr[idx1] # [1 4 5 7]
arr2 = arr[idx2] # [2 3 6 8]
You can use itertools for a one line solution:
import itertools
arr = [1, 2, 3, 4, 5, 6, 7, 8]
idx = [0, 3, 4, 6]
[(out_index, not_in_arr), (in_index, in_arr)] = [(a, list(b)) for a, b in itertools.groupby(sorted(arr, key=lambda x:arr.index(x) in idx), key=lambda x:arr.index(x) in idx)]
print(not_in_arr)
print(in_arr)
Output:
[2, 3, 6, 8]
[1, 4, 5, 7]
You can also map each value in arr to a dictionary, indicating if it's index is present in idx:
arr = [1, 2, 3, 4, 5, 6, 7, 8]
idx = [0, 3, 4, 6]
# converted to a set
idx_lookup = set(idx)
d = {x: True if i in idx_lookup else False for i, x in enumerate(arr)}
print(d)
Which gives this dictionay:
{1: True, 2: False, 3: False, 4: True, 5: True, 6: False, 7: True, 8: False}
I also converted idx to a set since in this case, duplicate indices are not necessary, and set/dictionary lookup is O(1). However, list lookup is O(n), so this optimization is worth it if possible.
Once you have this dictionary, you can filter out the elements you want to keep, and the rest of the elements from this:
keep = list(filter(lambda x: d[x], arr))
rest = list(filter(lambda x: not d[x], arr))
print(keep)
print(rest)
Which Outputs:
[1, 4, 5, 7]
[2, 3, 6, 8]
Note: You can also use list comprehensions above filtering of keep and rest:
keep = [x for x in arr if d[x]]
rest = [x for x in arr if not d[x]]
I didn't manage to correct a code I thought it would work for sure. Any advice to make the code functional is accepted.
Expected outputs of the following code is a list containing a cyclic permuation of the list
l = [1,2,3,4] (i.e : [[4, 1, 2, 3],[3, 4, 1, 2],[2, 3, 4, 1],[1, 2, 3, 4]])
Although what I get is : [[2, 3, 4, 1]]
The code :
def cycGen(l):
L=[]
while not(l in L) :
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
print(cycGen([1,2,3,4]))
Another variation of the solution is to consider the following code wich seems unfortunatly not working either :
def cycGen(l):
L=[]
for k in range(len(l)):
L.append(l)
for i in range(len(l)):
if l[i] == len(l) :
l[i]=1
else :
l[i] = 1 + l[i]
return L
Help me with your generous knowlege sharing please.
You can use collections.deque:
from collections import deque
a = [1, 2, 3, 4]
d = deque(a)
for _ in range(len(a)):
d.rotate()
print(list(d))
Which gives you the output:
[4, 1, 2, 3]
[3, 4, 1, 2]
[2, 3, 4, 1]
[1, 2, 3, 4]
As mentioned in Efficient way to shift a list in python
An easy way is just:
In [12]: x = [1,2,3,4]
In [13]: [x[i:]+x[:i] for i in range(len(x))]
Out[13]: [[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
In your first code sample, the line L.append(l) appends a "reference" (loosely speaking) to the list l to the end of L, rather than appending a copy as you seem to be expecting. Thus, when l is later modified, the reference to it contained in L is modified as well, and so when l in L is tested, l will equal the reference to itself in L, and so the loop will end. The same basic problem causes your second code sample to return multiples of the same list rather than several different lists.
To store a copy of l at the current point in time in L instead, use L.append(l[:]).
Here is an easy way:
>>> def cycGen(l):
size = len(l)
return [[l[(i+j)%size] for i in range(size)] for j in range(size)]
>>> l = [1,2,3,4]
>>> print cycGen(l)
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
You could do this using a generator too:
a = [1, 2, 3, 4]
def next_pos(max):
i = 0
while True:
for n in xrange(max):
yield n + i
i += 1
pos = next_pos(len(a))
b = []
for i in xrange(len(a)):
n = []
for j in xrange(len(a)):
m = pos.next()
if m >= len(a):
m -= len(a)
n.append(a[m])
b.append(n)
print b
output:
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
I have a list [[1, 2, 7], [1, 2, 3], [1, 2, 3, 7], [1, 2, 3, 5, 6, 7]] and I need [1,2,3,7] as final result (this is kind of reverse engineering). One logic is to check intersections -
while(i<dlistlen):
j=i+1
while(j<dlistlen):
il = dlist1[i]
jl = dlist1[j]
tmp = list(set(il) & set(jl))
print tmp
#print i,j
j=j+1
i=i+1
this is giving me output :
[1, 2]
[1, 2, 7]
[1, 2, 7]
[1, 2, 3]
[1, 2, 3]
[1, 2, 3, 7]
[]
Looks like I am close to getting [1,2,3,7] as my final answer, but can't figure out how. Please note, in the very first list (([[1, 2, 7], [1, 2, 3], [1, 2, 3, 7], [1, 2, 3, 5, 6, 7]] )) there may be more items leading to one more final answer besides [1,2,3,4]. But as of now, I need to extract only [1,2,3,7] .
Please note, this is not kind of homework, I am creating own clustering algorithm that fits my need.
You can use the Counter class to keep track of how often elements appear.
>>> from itertools import chain
>>> from collections import Counter
>>> l = [[1, 2, 7], [1, 2, 3], [1, 2, 3, 7], [1, 2, 3, 5, 6, 7]]
>>> #use chain(*l) to flatten the lists into a single list
>>> c = Counter(chain(*l))
>>> print c
Counter({1: 4, 2: 4, 3: 3, 7: 3, 5: 1, 6: 1})
>>> #sort keys in order of descending frequency
>>> sortedValues = sorted(c.keys(), key=lambda x: c[x], reverse=True)
>>> #show the four most common values
>>> print sortedValues[:4]
[1, 2, 3, 7]
>>> #alternatively, show the values that appear in more than 50% of all lists
>>> print [value for value, freq in c.iteritems() if float(freq) / len(l) > 0.50]
[1, 2, 3, 7]
It looks like you're trying to find the largest intersection of two list elements. This will do that:
from itertools import combinations
# convert all list elements to sets for speed
dlist = [set(x) for x in dlist]
intersections = (x & y for x, y in combinations(dlist, 2))
longest_intersection = max(intersections, key=len)
I have the following problem. Having a list of integers, I want to split it, into a list of lists, whenever the step between two elements of the original input list is not 1.
For example: input = [0, 1, 3, 5, 6, 7], output = [[0, 1], [3], [5, 6, 7]]
I wrote the following function, but it's uggly as hell, and I was wondering if anyone of you guys would help me get a nicer solution. I tried to use itertools, but couldn't solve it.
Here's my solution:
def _get_parts(list_of_indices):
lv = list_of_indices
tuples = zip(lv[:-1], lv[1:])
split_values = []
for i in tuples:
if i[1] - i[0] != 1:
split_values.append(i[1])
string = '/'.join([str(i) for i in lv])
substrings = []
for i in split_values:
part = string.split(str(i))
substrings.append(part[0])
string = string.lstrip(part[0])
substrings.append(string)
result = []
for i in substrings:
i = i.rstrip('/')
result.append([int(n) for n in i.split('/')])
return result
Thanks a lot!
This works with any iterable
>>> from itertools import groupby, count
>>> inp = [0, 1, 3, 5, 6, 7]
>>> [list(g) for k, g in groupby(inp, key=lambda i,j=count(): i-next(j))]
[[0, 1], [3], [5, 6, 7]]
def _get_parts(i, step=1):
o = []
for x in i:
if o and o[-1] and x - step == o[-1][-1]:
o[-1].append(x)
else:
o.append([x])
return o
_get_parts([0, 1, 3, 5, 6, 7], step=1)
# [[0, 1], [3], [5, 6, 7]])
Here is a solution utilizing a for loop.
def splitbystep(alist):
newlist = [[alist[0]]]
for i in range(1,len(alist)):
if alist[i] - alist[i-1] == 1:
newlist[-1].append(alist[i])
else:
newlist.append([alist[i]])
return newlist
This is how I'd do it:
inp = [0, 1, 3, 5, 6, 7]
base = []
for item in inp:
if not base or item - base[-1][-1] != 1: # If base is empty (first item) or diff isn't 1
base.append([item]) # Append a new list containing just one item
else:
base[-1].append(item) # Otherwise, add current item to the last stored list in base
print base # => [[0, 1], [3], [5, 6, 7]]
This is the textbook use case for function split_when from module more_itertools:
import more_itertools
print(list(more_itertools.split_when([0, 1, 3, 5, 6, 7], lambda x,y: y-x != 1)))
# [[0, 1], [3], [5, 6, 7]]
Or, even more simple with more_itertools.consecutive_groups:
print([list(g) for g in more_itertools.consecutive_groups([0, 1, 3, 5, 6, 7])])
# [[0, 1], [3], [5, 6, 7]]
Suppose I have a python list l=[1,2,3,4,5]. I would like to find all x-element lists starting with elements that satisfy a function f(e), or the sublist going to the end of l if there aren't enough items. For instance, suppose f(e) is e%2==0, and x=3 I'd like to get [[2,3,4],[4,5]].
Is there an elegant or "pythonic" way to do this?
>>> f = lambda e: e % 2 == 0
>>> x = 3
>>> l = [1, 2, 3, 4, 5]
>>> def makeSublists(lst, length, f):
for i in range(len(lst)):
if f(lst[i]):
yield lst[i:i+length]
>>> list(makeSublists(l, x, f))
[[2, 3, 4], [4, 5]]
>>> list(makeSublists(list(range(10)), 5, f))
[[0, 1, 2, 3, 4], [2, 3, 4, 5, 6], [4, 5, 6, 7, 8], [6, 7, 8, 9], [8, 9]]
Using a list comprehension:
>>> l = range(1,6)
>>> x = 3
>>> def f(e):
return e%2 == 0
>>> [l[i:i+x] for i, j in enumerate(l) if f(j)]
[[2, 3, 4], [4, 5]]