How to zip two sequences (one shifted by N elements)? [duplicate] - python

This question already has answers here:
How to iterate through two lists with one of them shifted?
(3 answers)
Closed 2 years ago.
I have two lists A and B and I want to traverse pairs of elements (A[0], B[2]), (A[1], B[3]), etc.
Without the shift I could just use zip(A, B) to do it efficently.
In this example the shift is 2 but may happen that I will need a shift of N. How to do it efficiently (not indexing into two lists)?

I think a concise way to do this would be
zipped = zip(list1, list2[n:])
Where n is an integer representing the offset.

Eventually, I arrived at the following generic function:
def zip_shift(s1, s2, shift, placeholder):
i1 = iter(s1)
i2 = iter(s2)
while shift > 0:
yield placeholder, next(i2) # leave only next(i2) if no placeholder pairs are needed
shift -= 1
yield from zip(i1, i2) # or return zip
The above function works like a generator that first fills in the placeholder values shift times instead of taking values from the second sequence s2. Afterward, it works just like zip. The yield from is a relatively new construct (since Python 3.3). There are subtle differences between yield from and return above but can be neglected in this situation.
Of course if the shift value is 1 almost (with the exception of the pairs with the placeholder) the same can be achieved with:
zip(s1, next(s2))
As with zip sequences do not have to be of the same length. The generator works as long as the shorter sequence is not exhausted.

Related

Write an generator/iterator expression for this sequence

I have this exercise that I fail to understand
Suppose we are given a list X of integers. We need to construct a sequence of indices (positions) of the elements in this list equal to the maximal element. The indicies in the sequence are in the ascending order.
Hint use the enumerator function
from typing import Iterator
X = [1,10,3,4,10,5]
S : Iterator[int] = YOUR_EXPRESSION
assert list(S)==[1,4]
This is the only thing I could come up with, but for sure it does not return [1,4]
If you wondering what I don't understand, it is not clear from reading the description how it could return [1,4].
Maybe you want to try to explain that to me first...
This is my (wrong) solution
my_enumerate=enumerate (X)
my_enumerate=(list(my_enumerate))
my_enumerate.sort(reverse=True)
So you have the list X containing [1,10,3,4,10,5]. The maximal, or largest, element is 10. Which means we should return a list of all the indices where we find 10. There are two 10s at index 1 and 4 respectively.
Using enumerate you get at each iteration the index and element. You can use that to filter out the elements you don't need. List comprehensions are useful in this case, allowing for filtering with the if syntax i.e. [val for val in items if some_condition]
you can use a generator like this
max_val=max(X)
s = (i for i, v in enumerate(X) if v==max_val)
This is my solution
( x[0] for x in enumerate (X) if x[1] == max(X) )
this is the book solution
(i for (i, n) in enumerate(X) if n == max(X))
This requires two steps:
Determine the maximum value with max
Iterate the indices of your list and retain those that have this maximum value
To avoid a bad time complexity, it is necessary to not repeat the first step:
S : Iterator[int] = (lambda mx:
(i for i, x in enumerate(X) if x == mx)
)(max(X))
The reason for presenting the code in such ugly expression, is that in the question it seems a requirement to follow the template, and only alter the part that is marked with "YOUR_EXPRESSION".
This is not how you would write it without such artificial constraints. You would just do mx = max(X) and then assign the iterator to S in the next statement without the need for this inline lambda.

Custom Key for Sort Function Doesn't Work

Given an array A[] of integers, A has to be sorted according to frequency of elements. If frequencies of two elements are same, then smaller number comes first.
I've tried to solve the problem using the following code using the sort function but my custom key for the sort() does not seem to work. Can someone tell me what's going on here?
'''a is the input array and n is it's sizeQ'''
def sortByFreq(a,n):
def count(k):
return n-a.count(k)
a.sort(key=int)
a.sort(key=count)
a=list(map(str,a))
answer=' '.join(a)
print(answer)
For an input array [9,9,9,2,5], the code is supposed to print 9 9 9 2 5, (as the array already is), but it prints 2 5 9 9 9 instead. (The second time I call sort it does not seem to work)
The problem is that you just cannot use the original list inside a sort key, because sort uses an out of place location to compute the sort.
At some point, the original a is empty. Don't expect something like "all elements of a are in it" when calling the sort key.
In fact, if you print a in the count method, you'll get an empty list, everytime.
The workaround is to make a copy of the list and use it in the sort key (aside: no need to pass the size of the list, since len can compute that)
def sortByFreq(a):
def count(k):
return len(a_copy)-a_copy.count(k)
a_copy = a.copy() # create a copy of the list
a.sort(key=count)
a=list(map(str,a))
answer=' '.join(a)
print(answer)
an alternative is to pre-count elements with a counter (uses hashes, so faster). Note that you have to store the length of a too.
def sortByFreq(a):
def count(k):
return n-c[k]
c = collections.Counter(a)
n = len(a)
a.sort(key=count)
finally, a shorter way would use reverse=True to simplify sort key, which we can turn to a lambda:
def sortByFreq(a):
c = collections.Counter(a)
a.sort(key=lambda k:c[k],reverse=True)
def sort_by_frequency(sequence):
"""Sort sequence by frequency."""
return ''.join(sorted([char for char in sequence], key=sequence.count, reverse=True))
if __name__ == '__main__':
print(sort_by_frequency('92959'))

Python: Use a Loop to Manipulate Arrays [duplicate]

This question already has answers here:
Extract first item of each sublist
(8 answers)
Closed 4 years ago.
I have to perform the same operation on a number of arrays. Is there a way to use a loop in Python to carry out this repetitive task?
For example, I have 5 arrays: A, B, C, D, and E.
I want to carry out the following:
A = A[0]
B = B[0]
C = C[0]
D = D[0]
E = E[0]
Is there any way to do this using a loop or some other technique to avoid typing almost the same thing multiple times?
My question has been marked as a duplicate of this question. There, the person is asking how to extract the first element from each list (or in my case array). I am not simply trying to extract the first element. I actually want to replace each array with it's first element -- literally A = A[0].
Some are saying this is not a good idea, but this is actually what I want to do. To give some context, I have code that leaves me with a number of 2D arrays, with shapes n x m. When n = 1, the first dimension is irrelevant, and I would like to dispense with that dimension, which is what A = A[0] does. My code needs to handle both cases where n = 1 and cases when n > 1.
In other words, when n = 1, my code results in an array A that is of the following form: A = array([[a]]), and I want to change it so that A = array([a]). And to reiterate, I need the flexibility of allowing n > 1, in which case A = array([[a1],[a2],...]). In that case, my code will not execute A = A[0].
The solution by Mark White below works, if you change the last line to:
A,B,C,D,E = [x[0] for x in [A,B,C,D,E]]
What's interesting is that this solution makes the code more compact, but actually involves as many characters as (an technically more than) the brute force approach.
I do think it is a pretty easy problem ,in my case ,I use three array ,but I think you can do five , my dear friend!
A = [1,3,4]
B = [2,4,5]
C = [54,5,6]
A,B,C = [x[0] for x in [A,B,C]]
Simply create a list of lists (or, specifically, references to A, B, C, etc.)
l = [A, B, C, D, E]
Then, you can iterate over l however you choose.
for i in range(len(l)):
l[i] = l[i][0]
Note that this will update l[i] rather than the lists (A, B, C, ...) themselves.

How to create a function that uses 2 integers from 2 different lists and adding the pair to a certain integer?

Doing some basic python coding. Here is the problem I was presented.
Create a function that takes 3 inputs:
Two lists of integers
one integer n
Prints the pairs of integers, one from the first input list and the other form the second list, that adds up to n. Each pair should be printed.
Final Result (Example):
pair([2,3,4], [5,7,9,12], 9)
2 7
4 5
I'm still awfully new to Python, studying for a test and for some reason this one keeps giving me some trouble. This is an intro course so basic coding is preferred. I probably won't understand most advanced coding.
The simplest naieve approach would be to just test all possible combinations to see if they add up.
def pair(list1, list2, x):
for a in list1:
for b in list2:
if a + b == x:
print a, b
There are more efficient ways to do it (eg. ignore duplicates, ignore numbers greater than x, etc.)
If you wanted to do it in a single loop, python has some convenience functions for that
from itertools import product
for a, b in product(list1, list2):
if a + b == x:
print a, b

Python sorted with list of alpha-numeric strings? [duplicate]

This question already has answers here:
Is there a built in function for string natural sort?
(23 answers)
Closed 8 years ago.
Here's the issue, I'm using the sorted function to arrange a list of alpha-numeric strings. The said strings have to numbers in them separated by a letter.
For instance: sortqns(['s1q1', 's10q1', 's1q2', 's10q10', 's10q2'])
def cmpqn(a, b):
if len(a) > len(b):
return 1
if len(a) < len(b):
return -1
if len(a) == len(b):
return 0
def sortqns(qnlist):
new = sorted(qnlist, cmp=cmpqn)
return new
Returns ['s1q1', 's1q2', 's10q1', 's10q2', 's10q10']
My problem is sorting the second digit:
sortqns(['s12q1', 's1q2', 's1q1'])
Returns ['s1q2', 's1q1', 's12q1']
Instead of:
Returning ['s1q1', 's1q2', 's12q1']
In the first example my desired return would be off if the first two items were swapped as well.
The sorting algorithm in list is stable. Stable sorting algorithms maintain the relative order of records with equal keys. Therefore, in your code, when two element have the same length, they will appear in the result maintained their relative order.
I think the following solution is helpful.
def sortqns(qnlist):
return sorted(qnlist, key = lambda x: (len(x), x))

Categories