HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonModerate

Weaving elements into a list

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
intolistweavingelements

Problem

I have the following problem statement:


Modify a given list such that one specific element is "weaved" into that list.


Examples if the element is 'module':



  • [] remains []



  • ['a'] remains ['a']



  • ['a', 'b'] becomes ['a', 'module', 'b']



  • ['a', 'b', 'c'] becomes ['a', 'module', 'b', 'module', 'c']




I solved it using the following code in Python 3.4:

@staticmethod
def __weave_element_into_list(element, values: list) -> list:
    """
    Weaves an element into a given list.

    Examples if the element is 'module':
     - Input [] remains [].
     - Input ['a'] remains ['a'].
     - Input ['a', 'b'] becomes ['a', 'module', 'b'].
     - Input ['a', 'b', 'c'] becomes ['a', 'module', 'b', 'module', 'c'].
     - etc.

    :param element: The element to weave into the list
    :param values:  The original list
    :return:    The list with element weaved into it.
    """
    copy_list = list(values)
    if len(copy_list) <= 1:
        return copy_list
    i = 1
    while i < len(copy_list):
        copy_list.insert(i, element)
        i += 2
    return copy_list


Is there a better (more Pythonic?) solution to it and is "weaving" the correct operation here?

Solution

The function could be replaced with this line:

return list(chain.from_iterable(zip(values, [element] * len(values))))[:-1]


Essentially,
zipping values with another list of the same size containing element in all values, flattening the zip, and chopping off the end.

About your original implementation, instead of this:

if len(copy_list) <= 1:
    return copy_list


This is more Pythonic:

if not copy_list:
    return copy_list


I'm also wondering if this needs to be a @staticmethod.
Since it's a pure function, I'd just call it weave.
Here's the complete implementation with doctests:

from itertools import chain

def weave(element, values: list) -> list:
    """
    >>> weave('module', [])
    []
    >>> weave('module', ['a'])
    ['a']
    >>> weave('module', ['a', 'b'])
    ['a', 'module', 'b']
    >>> weave('module', ['a', 'b', 'c'])
    ['a', 'module', 'b', 'module', 'c']

    :param element: The element to weave into the list
    :param values: The original list
    :return: The list with element weaved into it.
    """
    return list(chain.from_iterable(zip(values, [element] * len(values))))[:-1]


I see @jonrsharpe beat me to the doctests.
To add something new,
another way to run doctests:

python -m doctest yourfile.py


Update

Originally I proposed this one-liner:

return sum(zip(values, [element] * len(values)), ())[:-1]


But that turns out to be a bad idea.
This other discussion is also illuminating.

Code Snippets

return list(chain.from_iterable(zip(values, [element] * len(values))))[:-1]
if len(copy_list) <= 1:
    return copy_list
if not copy_list:
    return copy_list
from itertools import chain


def weave(element, values: list) -> list:
    """
    >>> weave('module', [])
    []
    >>> weave('module', ['a'])
    ['a']
    >>> weave('module', ['a', 'b'])
    ['a', 'module', 'b']
    >>> weave('module', ['a', 'b', 'c'])
    ['a', 'module', 'b', 'module', 'c']

    :param element: The element to weave into the list
    :param values: The original list
    :return: The list with element weaved into it.
    """
    return list(chain.from_iterable(zip(values, [element] * len(values))))[:-1]
python -m doctest yourfile.py

Context

StackExchange Code Review Q#92286, answer score: 11

Revisions (0)

No revisions yet.