Product with descreasing values - python

I have a 3 lists :
a = [10, 9, 8, 7, 6]
b = [8, 7, 6, 5, 4, 3]
c = [6, 5, 4, 3, 2]
I need to get all the permutations obtained with itertools.product(), BUT only if the values are decreasing:
[10, 8, 6] # is good
[6, 8, 4] # is not good, since 8 > 6
Is there a simple way to do it or should I go with list comprehension and conditions ?

You could do this with a list comprehension by looping over theitertools.product iterator and extracting only those returned items that are sorted in reverse:
[item for item in product(a,b,c) if sorted(item, reverse = True) == list(item)]
Example:
from itertools import product
a = [10,9,8,7,6]
b = [8, 7, 6, 5, 4, 3]
c = [6, 5, 4, 3, 2]
[item for item in product(a,b,c) if sorted(item, reverse = True) == list(item)]
# [(10, 8, 6), (10, 8, 5), (10, 8, 4), (10, 8, 3), (10, 8, 2) ...continues

You can refer following code which does not have list comprehensions:
from itertools import product
a = [10, 9, 8, 7, 6]
b = [8, 7, 6, 5, 4, 3]
c = [6, 5, 4, 3, 2]
for result in product(a,b,c):
if sorted(result, reverse = True) == list(result):
print result

This is a simple one line solution
>>> mylist = [10, 9, 8, 7, 6]
>>> all(earlier >= later for earlier, later in zip(mylist, mylist[1:]))
True
>>> mylist = [10, 9, 7, 8, 6]
>>> all(earlier >= later for earlier, later in zip(mylist, mylist[1:]))
False
I found this here:
Determine if a list is in descending order

If you don't want to use list comprehensions for some reason:
def decreasing(l):
return all(a >= b for a, b in zip(l[:-1], l[1:]))
filter(decreasing, product(a, b, c))

Related

Creating a list of N numbers from existing list each repeated K times

I believe this is an easy problem to solve. I have searched and found a few similar answers but not an efficient way to exactly what I want to achieve.
Assuming the following list:
x = [6, 7, 8]
I want to create a new list by repeating each number k times. Assuming k=3, the result should be:
xr = [6, 6, 6, 7, 7, 7, 8, 8, 8]
I was able to accomplish this using nest loops, which I believe is very inefficient:
xr = []
for num in x: # for each number in the list
for t in range(3): # repeat 3 times
xx2.append(num)
I also tried:
[list(itertools.repeat(x[i], 3)) for i in range(len(x))]
but I get:
[[6, 6, 6], [7, 7, 7], [8, 8, 8]]
Is there a more efficient direct method to accomplish this?
You can use list comprehension:
x = [6, 7, 8]
k = 3
out = [v for v in x for _ in range(k)]
print(out)
Prints:
[6, 6, 6, 7, 7, 7, 8, 8, 8]
def repeat_k(l,k):
lo = []
for x in l:
for i in range(k):
lo.append(x)
return lo
print (repeat_k([1,2,3],5))
Output:
[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]
With list comprehension:
def repeat_k(l,k):
return [ x for x in l for i in range(k) ]
print (repeat_k([1,2,3],5))
Output:
[1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3]
Another possibility:
>>> x = [6, 7, 8]
>>> k = 3
>>> l = []
>>> for item in x:
... l += k * [item]
...
>>> l
[6, 6, 6, 7, 7, 7, 8, 8, 8]
You can create a convenient function:
def repeat(it, n):
for elem in it: yield from [elem] * n
Use it like:
>>> list(repeat(x, n=3))
[6, 6, 6, 7, 7, 7, 8, 8, 8]
Thanks, everyone for the answers.
It seems there is an easier and more direct way to solve this using Numpy.
np.repeat(x, 3).tolist()
prints exactly what I needed:
[6, 6, 6, 7, 7, 7, 8, 8, 8]
import itertools
x=[4,5,6]
k=3
res = list(itertools.chain.from_iterable(itertools.repeat(i, K) for i in test_list))
print (res)
It can also be solved using python inbuilt functions of itertools library. The repeat function does the task of repetition and grouping into a list is done by the from_iterable function.

How can I find n smallest numbers without changing the order of the first list?

I intend to get the n smallest numbers in a list but keep the numbers in the same order they appear in the list. For example:
This is my list:
A = [1, 3, 4, 6, 7, 6, 8, 7, 2, 6, 8, 7, 0]
I like to get the first three lowest numbers as it has been ordered in the first list:
[1, 2, 0]
I do not want to sort the result as:
[0, 1, 2]
I have tried:
heapq.nsmallest(3,A)
but i wonder if it is possible to retain this list as:[1, 2, 0]
By the way, I'm not a Python coder so thanks for the help in advance.
You can try this:
new_a = []
A=[1, 3, 4, 6, 7, 6, 8, 7, 2, 6, 8, 7, 0]
for a in A:
if a not in new_a:
new_a.append(a)
new_a = [i for i in new_a if i in sorted(new_a)[:3]]
Output:
[1, 2, 0]
You could use heapq.nsmallest() to get the n smallest elements from the list. Then use collections.Counter to create a multiset from that list which you can use to check which elements from the original list to include in the result, e.g.
>>> from heapq import nsmallest
>>> from collections import Counter
>>> A = [1, 3, 4, 6, 7, 6, 8, 7, 2, 6, 8, 7, 0]
>>> n = 3
>>> c = Counter(nsmallest(n, A))
>>> result = []
>>> for elem in A:
... if c.get(elem, 0):
... result.append(elem)
... c[elem] -= 1
...
>>> result
[1, 2, 0]

Python Array Diff

Write a function or program that will take 2 arrays of integers, "current" and "target", and produce 2 arrays representing an additions list and a deletions list such that applying the additions and deletions to the "current" array will yield the "target" array.
For example, given the following
inputs:
current = [1, 3, 5, 6, 8, 9]
target = [1, 2, 5, 7, 9]
The outputs would be:
additions: [2, 7]
deletions: [3, 6, 8]
So that the following is true:
current([1, 3, 5, 6, 8, 9]) + additions([2, 7]) - deletions([3, 6, 8]) = target([1, 2, 5, 7, 9])
Solution:
So far I have this:
---------------------------
# import array function
from array import array
# create an integer array named current
current = array('i', [1, 3, 5, 6, 8, 9])
# add items from additions list into current array using the fromlist() method
additions = [2, 7]
current.fromlist(additions)
# remove items on deletions list from current array using the. remove() method
current.remove(3)
current.remove(6)
current.remove(8)
It will work for you...
def addlist(current,target):
add = []
intersection = set(current) & set(target)
for i in target:
if i not in intersection:
add.append(i)
return add
def removeList(current,target):
remove = []
intersection = set(current) & set(target)
for i in current:
if i not in intersection:
remove.append(i)
return remove
def main():
current = [1, 3, 5, 6, 8, 9]
target = [1, 2, 5, 7, 9]
print(addlist(current,target))
print(removeList(current,target))
if __name__=="__main__":
main()
Below one should be easy to understand.
>>> current = [1, 3, 5, 6, 8, 9]
>>> target = [1, 2, 5, 7, 9]
>>> set(current) & set(target)
set([1, 5, 9])
>>> unique = list(set(current) & set(target))
>>> additions = [i for i in target if i not in unique]
>>> additions
[2, 7]
>>> deletions = [i for i in current if i not in unique]
>>> deletions
[3, 6, 8]
>>>
This will work as well.
current = [1, 3, 5, 6, 8, 9]
target = [1, 2, 5, 7, 9]
additions=[x for x in target if x not in current]
deletions=[x for x in current if x not in target]

Extracting ordered sub sequence from list

I am trying to extract ORDERED sequence. For example,
a = [2, 3, 1, 4, 6, 8, 5, 9]
b = [3, 8, 9, 4, 10, 11, 5]
c = [3,4,5]
c must hold values common to a and b where [3,4,5] appear in an order, [8,9] must not appear because it comes between [3,4] in a and between [4,5] in b
Another example as follows:
a = [2, 3, 1, 4, 6, 8, 9, 10]
b = [2, 8, 3, 9, 10, 11]
c = [2,3,9,10]
I tried the following code:
a = [2, 3, 1, 4, 6, 8, 5, 9]
b = [3, 8, 9, 4, 10, 11, 5]
for i in a:
for j in b:
if i==j:
print i
break
I get the WRONG results as follows:
3
4
8
5
9
How do I avoid getting such an output? Also is there a pythonic way to this?
Use a tempval and store the context. This can be done using the enumerate builtin function. Now using slices you will get the output as expected.
a = [2, 3, 1, 4, 6, 8, 5, 9]
b = [3, 8, 9, 4, 10, 11, 5]
tempval = 0
for i in a:
for ind,j in enumerate(b[tempval:]):
if i==j:
print i
tempval = ind
Output is
3
4
5
#Ekoji, To get the list in order, you can try the below code. Sort the elements in the list a, So you get them in order.
a = [2, 3, 1, 4, 6, 8, 5, 9]
b = [3, 8, 9, 4, 10, 11, 5]
a.sort()
# use your logic
for i in a:
for j in b:
if i == j:
print ("i is : %s j is :%s" % (i , j))
if len(c) > 1:
print c
print ("validation : %s :%s" %( c[-1] , i-1))
if c[-1:] == [i-1]:
print "continue"
c.append(i)
else:
print "do Nothing"
else:
c.append(i)
print c
Output :
[3, 4]
validation : 4 :4
continue
[3, 4, 5]
validation : 5 :7
do Nothing
[3, 4, 5]
validation : 5 :8
do Nothing
[3, 4, 5]

Reorder Python List

I have a list of 4 items like this:
a, b, c, d = [1, 2, 3, 4]
I'm reordering the list, flipping each pair:
[b, a, d, c]
Is there a way to do this in one expression? I've tried using list comprehension and unpacking, but can't seem to get it right.
I have [1, 2, 3, 4]. I'm trying to get [2, 1, 4, 3].
More generically, if you're looking to flip pairs of numbers in a list:
>>> L = [1, 2, 3, 4, 5, 6]
>>> from itertools import chain
>>> list(chain.from_iterable(zip(L[1::2], L[::2])))
[2, 1, 4, 3, 6, 5]
Look at this:
>>> lst = [1, 2, 3, 4]
>>> [y for x in zip(*[iter(lst)]*2) for y in x[::-1]]
[2, 1, 4, 3]
>>>
>>> lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> [y for x in zip(*[iter(lst)]*2) for y in x[::-1]]
[2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
>>>
If this is only about 4 member lists - this would suffice:
list = [1, 2, 3, 4]
reordered_list = [list[1], list[0], list[3],list[2]]
Because absolutely nobody has given an answer that works on generic iterables,
from itertools import chain
items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
zip(*[iter(items)]*2)
#>>> <zip object at 0x7fd673afd050>
[itms for itms in zip(*[iter(items)]*2)]
#>>> [(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]
So zip(*[iter(x)]*2) means ix = iter(x); zip(ix, ix) which pairs each element.
Then you can reverse:
[(y, x) for (x, y) in zip(*[iter(items)]*2)]
#>>> [(2, 1), (4, 3), (6, 5), (8, 7), (10, 9)]
Putting it all together and flattening:
[itm for (x, y) in zip(*[iter(items)]*2) for itm in (y, x)]
#>>> [2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
It's generic and short!
If you want something faster at the expense of genericism, you'll be hard pressed to better this:
new = list(items)
new[::2], new[1::2] = new[1::2], new[::2]
new
#>>> [2, 1, 4, 3, 6, 5, 8, 7, 10, 9]
Note that this still works on arbitrary iterables, but there are fewer layers of abstraction; you can't bump up the size of the flipped sub-lists as easily and can't output iterables, etc.
Do you mean this:
>>> a, b, c, d = [1, 2, 3, 4]
>>> b, a, d, c = a, b, c, d
>>> a
2
>>> b
1
>>> c
4
>>> d
3
?
Try this list comprenhension solution:
a = [1,2,3,4,5,6] # Any list with even number of elements
b = [a[e+1] if (e%2 == 0) else a[e-1] for e in range(len(a))]
This just works if the list a have an even number of elements.
In [1]: l = [1, 2, 3, 4]
In [2]: list(chain(*map(reversed, zip(l[::2], l[1::2]))))
Out[2]: [2, 1, 4, 3]
Am I missing something? Reorder given_list with a loop:
rez = []
for i in range(len(given_list)-1, -1, -1):
rez.append(given_list[i])
return rez

Categories