2

Probably a very naive question:

I have a list:

color = ["red","blue","red","green","blue"]

Now, I want to iterate through the list

for c in color:
   # color is "red"
     get the rest of the colors except this red
    so rest = ["blue","red","green",blue"]

in next iteration:

    c = blue
    rest = ["red","red","green","blue"]

Eh. why do i have a feeling that this is pretty trivial to do..and there is probably a one line command which can solve this out? Thanks

1
  • Are you looking for list.pop()? It removes and returns one item from a list. Commented May 3, 2012 at 20:26

6 Answers 6

6

The easiest way to think of this is that you want to iterate through every combination with a length one less than the list. To do this, we can use itertools.combinations():

import itertools

color = ["red","blue","red","green","blue"]

for rest in itertools.combinations(color, len(color)-1):
    print(rest)

Which gives us:

('red', 'blue', 'red', 'green')
('red', 'blue', 'red', 'blue')
('red', 'blue', 'green', 'blue')
('red', 'red', 'green', 'blue')
('blue', 'red', 'green', 'blue')

This is a good solution as it works on iterables as well as sequences, is very readable, and should be nice and fast.

If you also need the current value, you can also get that easily, as combinations() gives you a predictable order, so we just iterate through both at the same time with zip() (naturally, if you want the best performance, use itertools.izip() under Python 2.x, as zip() creates a list, not a generator as in 3.x).

import itertools

color = ["red","blue","red","green","blue"]

for c, rest in zip(color, itertools.combinations(reversed(color), len(color)-1)):
    print(c, rest)

red ('blue', 'green', 'red', 'blue')
blue ('blue', 'green', 'red', 'red')
red ('blue', 'green', 'blue', 'red')
green ('blue', 'red', 'blue', 'red')
blue ('green', 'red', 'blue', 'red')

Here I reverse the input for comibinations() so it works from left to right - you can reverse color in the zip() instead to get right to left.

So yes, in short, it's a one line solution (two if you count the import).

Sign up to request clarification or add additional context in comments.

3 Comments

The current implementation of combinations() might give a predictable order, but I wouldn't rely on it to remain the same in future implementations.
@spinlok The order for combinations is guaranteed.
@spinlok It's a documented feature of the function - it would be a breaking change to change it.
1

Slicing and enumerate make easy work of this task:

>>> colors = ["red", "blue", "red", "green", "blue"]
>>> for i, color in enumerate(colors):
        rest = colors[:i] + colors[i+1:]
        print color, '-->', rest

red --> ['blue', 'red', 'green', 'blue']
blue --> ['red', 'red', 'green', 'blue']
red --> ['red', 'blue', 'green', 'blue']
green --> ['red', 'blue', 'red', 'blue']
blue --> ['red', 'blue', 'red', 'green']

The enumerate tracks the position of each color and the slices extract the parts of the list before and after the color.

2 Comments

@AshwiniChaudhary Actually, slicing as fast or faster than any other method of building a list (much of the code for list(s), l.extend(s), and l[:] = s is the same underlying code). Also, slicing will pre-size the target list so that no resizes are necessary. IOW, you minus one is not only unwarranted, it is simply incorrect.
sorry for the incomplete comment, what I meant to say is that the slicing is an easier way but your solution is slow because you're adding two list using '+', which makes it slow.Am i wrong here?
1

This should also work

for i in range(len(yourlist)):
    newlist = yourlist[:i] + yourlist[i:]

Comments

0

This Python code will create a new output list without the duplicates.

done = []
for c in color:
    if c in done:
        continue
    done.append(c)
    print c

Comments

0

The following example will return a list with duplicates removed. It starts with an empty return list, checks the color list, and, if a color, in this case red, is already in the output, it is ignored.

#!/usr/bin/env python

color = ["red","blue","red","green","blue"]

def rem_dup(dup_list):
    corrected_list = []
    for color in dup_list:
        if color in corrected_list:
            continue
        else:
            corrected_list.append(color)

    return corrected_list

You would probably be better off using something like

>>> set(color)
set(['blue', 'green', 'red'])
>>> 

or

>>> import collections
>>> color = ["red","blue","red","green","blue"]
>>> collections.OrderedDict.fromkeys(color)
OrderedDict([('red', None), ('blue', None), ('green', None)])
>>> 

to remove duplicates. Both are more efficient than the for loop.

Comments

-2
for idx, item in enumerate(color):
    print 'I am %s' % item
    rest = color[:idx] + color[idx+1:]
    print 'Rest is %s' % ','.join(rest)

3 Comments

@AshwiniChaudhary, no it isn't. I'd refrain from downvoting based on inaccurate knowledge.
your solution is slow because you're adding two list using '+', I've timed it using timeit module, check my solution.
Just because it might be slow doesn't mean it's too slow. I might not have upvoted the answer, but I see no reason to downvote it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.