1

I have a piece of codes as follows:

ascii_key = [None]*(len(ascii_username) + len(ascii_password))
ascii_key[0::2] = ascii_username
ascii_key[1::2] = ascii_password

I keep on getting the following error:

ValueError: attempt to assign sequence of size 8 to extended slice of size 6

I think it has something to do with the fact that it wants me filling the entire extended list exactly, and if it is the case is there a way I can combine the two lists before it gets mad?

The ideal process is lists ["A", "B", "C"] and ["D", "E", "F"] become

["A", "D", "B", "E", "C", "F"]

I tried following the solution from this post Pythonic way to combine two lists in an alternating fashion?

-Apologies in advance, I am a novice programmer.

youngdev
  • 31
  • 6
  • I am not getting any error when I ran your code. I am getting the expected result. I think you should keep the size of both "ascii_username" and "ascii_password" same. – abhishek kumar Feb 11 '20 at 08:53

2 Answers2

3

What you are trying to do is an interleave of two sequences. The reason you are seeing the error is because ascii_username and ascii_password are not the same length. When you are trying to assign to the slice of the list, you have to supply the exact number of elements in the slice.

It is easy to see in this example: slicing x at step size of 2 has more elements than y.

x = [1, 2, 3, 4, 5, 6, 7, 8]
y = 'yes'
z = 'nope!'

print(x[::2])
# prints:
[1, 3, 5, 7]
print(list(y))
['y', 'e', 's']

Trying to assign to x[::2] leaves a dangling 7 that is not reassigned.

To fix this problem, you can use interleave_longest from the more_itertools package.

from more_itertools import interleave_longest

list(interleave_longest(x, y))
# returns:
['y', 'n', 'e', 'o', 's', 'p', 'e', '!']

Or if you don't want to install a new package, the source code for the function is pretty small.

from itertools import chain, zip_longest

_marker = object()

def interleave_longest(*iterables):
    """Return a new iterable yielding from each iterable in turn,
    skipping any that are exhausted.

        >>> list(interleave_longest([1, 2, 3], [4, 5], [6, 7, 8]))
        [1, 4, 6, 2, 5, 7, 3, 8]

    This function produces the same output as :func:`roundrobin`, but may
    perform better for some inputs (in particular when the number of iterables
    is large).

    """
    i = chain.from_iterable(zip_longest(*iterables, fillvalue=_marker))
    return [x for x in i if x is not _marker]


interleave_longest(x, y)
# returns:
['y', 'n', 'e', 'o', 's', 'p', 'e', '!']
James
  • 32,991
  • 4
  • 47
  • 70
  • I appreciate this solution, I was trying the roundrobin and zip methods submitted to this post but I'm not sure my programming capacity is there quite yet. It's concise and I know what's going on. Just gotta figure out how to install the package – youngdev Feb 11 '20 at 09:01
  • You actually don't need to install it if iterleaving is all you need. You can just copy the last block of code and it will work. – James Feb 11 '20 at 09:03
  • My only objection is that I'm gonna have to spend a load of time thoroughly figuring it out. I'm trying not to use any code that I don't 100% understand. I'll do it for this one though – youngdev Feb 11 '20 at 09:08
1

For that task you might use roundrobin as shown in itertools recipes

from itertools import cycle, islice
def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    num_active = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while num_active:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            # Remove the iterator we just exhausted from the cycle.
            num_active -= 1
            nexts = cycle(islice(nexts, num_active))

Then:

t1 = ['A', 'B', 'C']
t2 = ['D', 'E', 'F']
interleaved = list(roundrobin(t1,t2))
print(interleaved)  # ['A', 'D', 'B', 'E', 'C', 'F']

Note that as roundrobin(t1,t2) is generator I feed it into list function to get list. It will use all elements, for example for t1 = ['A', 'B', 'C'], t2 = ['D', 'E', 'F', 'G', 'H'] result is ['A', 'D', 'B', 'E', 'C', 'F', 'G', 'H'].

Daweo
  • 31,313
  • 3
  • 12
  • 25