0

I've been writing some code that involves inserting random characters into a list, and then removing those characters. Imagine you have a string:

['x', 'x', 'x', 'x', 'x', 'x', 'x', 'x']

With this as an input, you get this as an output:

['x', 'x', 'a', 'r', 'x', 'x', 't', 'q', 'x', 'x' 'j', 'z', 'x', 'x']

I have this code written. I tried this for removing those random characters:

iterations = 0
removal = 0
for s in my_list:
if iterations % 3 == 0:
    removal = 0
    for letters in range(2):
        del my_list[removal + iterations]
    removal += 1
iterations += 1

This just removes some of them, and I can't really figure out the pattern. The idea is that this would be able to take out, say, five characters every eight iterations through a list. Or any number of characters every any number iterations.

jme
  • 19,895
  • 6
  • 41
  • 39
  • 3
    Mutating a `list` like that will lead to trouble, as the indices will move around after each mutation. – TigerhawkT3 Nov 29 '15 at 03:10
  • could you give an example of how the output should look like depending on the `characters` and `iterations` that you want to parameterize? – eugecm Nov 29 '15 at 03:13
  • 2
    See: [Removing Item From List - during iteration - what's wrong with this idiom?](http://stackoverflow.com/questions/2896752/removing-item-from-list-during-iteration-whats-wrong-with-this-idiom) – jme Nov 29 '15 at 03:15
  • Check your whitespace. I think you may have left out an indent when you copied from IDE to the stackoverflow input box. – michen00 Nov 29 '15 at 04:02
  • Could be the case; I just typed it over because I'm switching between OS's to get to my IDE. It's a really pathetic solution. – theDoctor5000 Nov 29 '15 at 16:40

4 Answers4

1

if you can insert character in order pattern, then you should have to ability to remove those characters in the same order.

Well, assume that insert the character 2 times and the position to insert is 3. Then you need to remove the every 4th elements first

>>>for i in range(3, len(my_list), 3):
       my_list.pop(i) # I have a problem with my python, so I could only use pop() to remove
['x', 'x', 'a', 'x', 'x', 't', 'x', 'x' 'j', 'x', 'x']

Then you need to remove every 3rd elements

>>>for i in range(2, len(my_list), 2):
       my_list.pop(i)
['x', 'x', 'x', 'x', 'x', 'x', 'x', 'x']
AkaKaras
  • 102
  • 1
  • 4
0

As one of the commenters noted, it is not going to be easy to randomly start removing items from a list based on indices. What I would do to solve this problem would be to store some random value in the indices you want to remove than filter the array into a new array by checking if for that value.

   iterations = 0
   removal = 0
   placeholder = "TO_DELETE"

   for s in my_list:
     if iterations % 3 == 0:
       removal = 0
     for letters in range(2):
       my_list[removal + iterations] = placeholder
     removal += 1
     iterations += 1

   my_list = [i for i in my_list if i != placeholder]
pech0rin
  • 4,588
  • 3
  • 18
  • 22
  • This is great. I considered doing this, however for the purposes of the application, I would prefer that these random characters are discreet (as in inconspicuous, not the opposite of continuous.) In reality, the list will contain many characters that aren't all 'x'. – theDoctor5000 Nov 29 '15 at 16:44
0

The issue you're encountering in your code is that of modifying a list while iterating over it.

Here's an alternative approach using cycle from itertools:

from itertools import cycle

def stride(iterable, take, leave):
    pattern = cycle([True] * take + [False] * leave)

    for value, take in zip(iterable, pattern):
        if take:
            yield value

Such that if x = ['x', 'x', 'a', 'r', 'x', 'x', 't', 'q', 'x', 'x', 'j', 'z', 'x', 'x'], then:

>>> list(stride(x, 2, 2))
['x', 'x', 'x', 'x', 'x', 'x', 'x', 'x']

If take or leave is large, then this wastes memory by making a pattern list of size take + leave. So instead we can make a generator helper function:

def take_or_leave(take, leave):
    while True:
        for _ in range(take):
            yield True
        for _ in range(leave):
            yield False

def stride(iterable, take, leave):
    pattern = take_or_leave(take, leave)
    for value, take in zip(iterable, pattern):
        if take:
            yield value
jme
  • 19,895
  • 6
  • 41
  • 39
  • Thanks for the feedback. I'm looking for a solution that doesn't have to worry about dependencies during packaging, so I'm trying to do things without modules. – theDoctor5000 Nov 29 '15 at 16:46
  • @theDoctor5000 `itertools` is in the standard library. There is therefore no dependency issue -- anyone who has python has `itertools`. Furthermore, the second approach uses no imports whatsoever. – jme Nov 29 '15 at 17:22
  • Ok. This might be what I ultimately implement. Thanks – theDoctor5000 Nov 29 '15 at 17:32
-2

I like approaching these sorts of things with wonky one-liner functions. Here's what I have:

removeStuff = lambda myArray, delEvery: [myArray[x] for x in range(len(myArray)) if x%delEvery!=0]

Usage:

>>> removeStuff([1,2,3,4,5,6,7], 3)
[2, 3, 5, 6]
Samie Bencherif
  • 1,285
  • 12
  • 27