Seite 1 von 2

l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Mittwoch 20. August 2014, 15:19
von jens
Wie kann ich aufeinander folgende Einträge in einer Liste durch einen anderen ersetzten?

also preudocode:

Code: Alles auswählen

l=[1,2,3,4]
l=l.replace([2,3], "X")
print l
[1,"X",4]

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Mittwoch 20. August 2014, 15:34
von EyDu
Für zwei Elemente:

Code: Alles auswählen

[("X" if x == (2, 3) else x) for (x, y) in zip(l, l[1:])] 
Oder direkt eine ordentliche und allgemeine Funktion. Die ist wahrscheinlich keine zehn Zeilen lang.

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Mittwoch 20. August 2014, 15:35
von jens
Oh, super Idee! Mal testen...

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Mittwoch 20. August 2014, 15:40
von EyDu
Ein Problem mit meinem Ansatz gibt es natürlich dann, wenn zwei identische Werte ersetzt werden sollen. Also in einer Liste [1, 2, 2, 2, 3] der Werte [2, 2] ersetzt werden soll. Das ergäbe dann [1, X, X, 3].

Ach, und es muss natürlich

Code: Alles auswählen

[("X" if (x, y) == (2, 3) else x) for (x, y) in zip(l, l[1:])]
heißen, bzw. ohne Dekonstruktion:

Code: Alles auswählen

[("X" if elem == (2, 3) else elem[0]) for elem in zip(l, l[1:])]

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Mittwoch 20. August 2014, 15:46
von jens
Ne, so einfach ist das nicht:

Code: Alles auswählen

def list_replace_tuples(l, src, dst):
    """
    >>> list_replace_tuples([1,2,3,4], (2,3), "X")
    [1, 'X', 4]
    
    >>> list_replace_tuples([1,2,3,4,5], (4,5), "X")
    [1, 2, 3, 'X']
    
    >>> list_replace_tuples([1,2,3,4,5], (1,2), "X")
    ['X', 3, 4, 5]
    
    >>> list_replace_tuples([1,2,3,3,3,4,5], (3,3), "X")
    [1, 2, 'X', 'X', 3, 4, 5]
    """
    assert len(src)==2
    return  [
        (dst if elem == src else elem[0]) for elem in zip(l, l[1:])
    ]

if __name__ == "__main__":
    import doctest
    print doctest.testmod()
Ausgabe:

Code: Alles auswählen

**********************************************************************
File "/media/servershare/workspace/DragonPy/dragonlib/core/test.py", line 3, in __main__.list_replace_tuples
Failed example:
    list_replace_tuples([1,2,3,4], (2,3), "X")
Expected:
    [1, 'X', 4]
Got:
    [2, 'X', 4]
**********************************************************************
File "/media/servershare/workspace/DragonPy/dragonlib/core/test.py", line 6, in __main__.list_replace_tuples
Failed example:
    list_replace_tuples([1,2,3,4,5], (4,5), "X")
Expected:
    [1, 2, 3, 'X']
Got:
    [2, 3, 4, 'X']
**********************************************************************
File "/media/servershare/workspace/DragonPy/dragonlib/core/test.py", line 12, in __main__.list_replace_tuples
Failed example:
    list_replace_tuples([1,2,3,3,3,4,5], (3,3), "X")
Expected:
    [1, 2, 'X', 'X', 3, 4, 5]
Got:
    [2, 3, 'X', 'X', 4, 5]
**********************************************************************
1 items had failures:
   3 of   4 in __main__.list_replace_tuples
***Test Failed*** 3 failures.
TestResults(failed=3, attempted=4)
Man kann auch statt elem[0] auch elem[1] nehmen. Aber dann fehlt halt der andere Teil...

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Mittwoch 20. August 2014, 15:52
von EyDu
Da has du natürlich Recht. Ein wenig Nachdenken vor dem Posten hätte wohl geholfen :oops:

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Mittwoch 20. August 2014, 15:57
von EyDu

Code: Alles auswählen

def replace(l, old, new):
    index = 0
    
    while index < len(l):
        element = l[index:index+len(old)]
        
        if element == old:
            yield new
            index += len(old)
        else:
            yield l[index]
            index += 1
Natürlich wieder ungetestet.

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Mittwoch 20. August 2014, 16:06
von jens
Treffer:

Code: Alles auswählen

def list_replace_tuples(l, src, dst):
    """
    >>> list_replace_tuples([1,2,3,4], (2,3), "X")
    [1, 'X', 4]
    
    >>> list_replace_tuples([1,2,3], (2,), "X")
    [1, 'X', 3]
    
    >>> list_replace_tuples([1,2,3,4,5], (2,3,4), "X")
    [1, 'X', 5]
    
    >>> list_replace_tuples([1,2,3,4,5], (4,5), "X")
    [1, 2, 3, 'X']
    
    >>> list_replace_tuples([1,2,3,4,5], (1,2), "X")
    ['X', 3, 4, 5]
    
    >>> list_replace_tuples([1,2,3,3,3,4,5], (3,3), "X")
    [1, 2, 'X', 3, 4, 5]
    """
    result=[]
    src=list(src)
    src_len=len(src)
    index = 0
    while index < len(l):
        element = l[index:index+src_len]
        #print element, src
        if element == src:
            result += dst
            index += src_len
        else:
            result.append(l[index])
            index += 1
    return result

if __name__ == "__main__":
    import doctest
    print doctest.testmod()
Test läuft durch ;)

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 01:22
von snafu

Code: Alles auswählen

def iter_replace(iterable, needle, replacement):
    """
    >>> list(iter_replace([1,2,3,4], (2,3), "X"))
    [1, 'X', 4]

    >>> list(iter_replace([1,2,3], (2,), "X"))
    [1, 'X', 3]

    >>> list(iter_replace([1,2,3,4,5], (2,3,4), "X"))
    [1, 'X', 5]

    >>> list(iter_replace([1,2,3,4,5], (4,5), "X"))
    [1, 2, 3, 'X']

    >>> list(iter_replace([1,2,3,4,5], (1,2), "X"))
    ['X', 3, 4, 5]

    >>> list(iter_replace([1,2,3,3,3,4,5], (3,3), "X"))
    [1, 2, 'X', 3, 4, 5]
    """
    picked = []
    for item in iterable:
        if item == needle[len(picked)]:
            picked.append(item)
            if len(picked) == len(needle):
                del picked[:]
                yield replacement
        else:
            for picked_item in picked:
                yield picked_item
            del picked[:]
            yield item


if __name__ == "__main__":
    import doctest
    print doctest.testmod()

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 09:12
von Sirius3
@snafu: der Testfall

Code: Alles auswählen

>>> list(iter_replace([1,2,2,3,4,5],[2,3], "X"))
[1, 2, 2, 3, 4, 5]
fehlt, richtig wäre:

Code: Alles auswählen

>>> list(iter_replace([1,2,2,3,4,5],[2,3], "X"))
[1, 2, 'X', 4, 5]
Hier eine Variante mit deque:

Code: Alles auswählen

from collections import deque
from itertools import islice

def iter_replace(iterable, needle, replacement):
    """
   >>> list(iter_replace([1,2,3,4], (2,3), "X"))
   [1, 'X', 4]
 
   >>> list(iter_replace([1,2,3], (2,), "X"))
   [1, 'X', 3]
 
   >>> list(iter_replace([1,2,3,4,5], (2,3,4), "X"))
   [1, 'X', 5]
 
   >>> list(iter_replace([1,2,3,4,5], (4,5), "X"))
   [1, 2, 3, 'X']
 
   >>> list(iter_replace([1,2,3,4,5], (1,2), "X"))
   ['X', 3, 4, 5]
 
   >>> list(iter_replace([1,2,3,3,3,4,5], (3,3), "X"))
   [1, 2, 'X', 3, 4, 5]

   >>> list(iter_replace([1,2,2,3,4,5], (2,3), "X"))
   [1, 2, 'X', 4, 5]
   """
    iterable = iter(iterable)
    needle = deque(needle)
    picked = deque(islice(iterable, len(needle)-1))
    for item in iterable:
        picked.append(item)
        if needle == picked:
            yield replacement
            picked = deque(islice(iterable, len(needle)-1))
        else:
            yield picked.popleft()
    for item in picked:
        yield item

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 09:43
von snafu
Erweiterung meiner Variante:

Code: Alles auswählen

def iter_replace(iterable, needle, replacement):
    """
    >>> list(iter_replace([1,2,3,4], (2,3), "X"))
    [1, 'X', 4]

    >>> list(iter_replace([1,2,3], (2,), "X"))
    [1, 'X', 3]

    >>> list(iter_replace([1,2,3,4,5], (2,3,4), "X"))
    [1, 'X', 5]

    >>> list(iter_replace([1,2,3,4,5], (4,5), "X"))
    [1, 2, 3, 'X']

    >>> list(iter_replace([1,2,3,4,5], (1,2), "X"))
    ['X', 3, 4, 5]

    >>> list(iter_replace([1,2,3,3,3,4,5], (3,3), "X"))
    [1, 2, 'X', 3, 4, 5]

    >>> list(iter_replace([1,2,2,3,4,5], (2,3), "X"))
    [1, 2, 'X', 4, 5]
    """
    picked = []
    for item in iterable:
        if item == needle[len(picked)]:
            picked.append(item)
            if len(picked) == len(needle):
                del picked[:]
                yield replacement
        elif len(picked) == 1 and item == picked[0]:
            yield item
        else:
            for picked_item in picked:
                yield picked_item
            del picked[:]
            yield item


if __name__ == "__main__":
    import doctest
    print doctest.testmod()

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 10:41
von Sirius3
@snafu: dann kannst Du gleich auf 2-elementige Wiederholungen im Pattern erweitern ;-)

Code: Alles auswählen

>>> list(iter_replace([1,2,3,2,3,2,3,3,4,5], (2,3,2,3,3), 'X'))
[1, 2, 3, 2, 3, 2, 3, 3, 4, 5]
statt

Code: Alles auswählen

>>> list(iter_replace([1,2,3,2,3,2,3,3,4,5], (2,3,2,3,3), 'X'))
[1, 2, 3, 'X', 4, 5]

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 11:41
von snafu
Nagut... :evil:

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 12:55
von jens
Ob man das nicht eigentlich als Feature Request einreichen könnte? Also ein l=l.replace([2,3], "X") ?

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 13:41
von BlackJack
@jens: Unter welchem Namen? `replace()` geht ja nicht, das gibt es schon und das hat für diese Argumente bereits eine Bedeutung.

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 13:48
von jens
Warum nicht replace? Eine liste hat doch kein replace, oder was meinst du?

Halt das selbe was string.replace macht (pseudocode):

Code: Alles auswählen

s="12345"
print s.replace("3","X")
"12X45"

l=[1,2,3,4,5]
print l.replace(3,"X")
[1,2,"X",4,5]

print l.replace([2,3,4],"Y")
[1,"Y",5]

print l.replace([2,3,4],["X","Y"])
[1,"X","Y",5]

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 13:56
von BlackJack
@jens: Ups, die Methode gibt's tatsächlich nicht. Aber die wäre *so* für mich unerwartet. Ich hätte erwartet das die beiden Argumente das alte und das neue Element sind, also bei ``print l.replace([2,3,4],"Y")`` hätte ich keine Änderung erwartet weil in der Liste kein Element mit dem Wert [2,3,4] vorkommt. Bei ``l = [42, [2, 3, 4], 'spam']`` würde ich dann allerdings [42, 'Y', 'spam'] als Ergebnis erwarten.

Das heisst eigentlich jedes mal `None` denn `replace()` verändert ja die Liste und erstellt keine neue. (Oder?)

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 14:12
von jens
Mein das so:

Code: Alles auswählen

class List2(list):
    def replace(self, src, dst):
        """
        >>> l=List2([1,2,3,4])
        >>> l
        [1, 2, 3, 4]
        >>> l.replace((2,3), "X")
        [1, 'X', 4]

        >>> l=List2([1,2,3,4])
        >>> l.replace([2], "X")
        [1, 'X', 3, 4]

        >>> l=List2([1,2,3,4,5])
        >>> l.replace([2,3,4], "X")
        [1, 'X', 5]

        >>> l=List2([1,2,3,4,5])
        >>> l.replace((4,5), "X")
        [1, 2, 3, 'X']

        >>> l=List2([1,2,3,4,5])
        >>> l.replace((1,2), "X")
        ['X', 3, 4, 5]

        >>> l=List2([1,2,3,3,3,4,5])
        >>> l.replace((3,3), "X")
        [1, 2, 'X', 3, 4, 5]
        """
        result=[]
        src=list(src)
        src_len=len(src)
        index = 0
        while index < len(self):
            element = self[index:index+src_len]
            #print element, src
            if element == src:
                result += dst
                index += src_len
            else:
                result.append(self[index])
                index += 1
        return result



if __name__ == "__main__":
    import doctest
    print doctest.testmod(verbose=0)
    print " --- END --- "

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 14:14
von BlackJack
@jens: Habe das schon verstanden, aber das finde ich sehr komisch. Ich hätte da etwas anderes erwartet.

Re: l=[1,2,3,4] ; l=l.replace([2,3], "X") ???

Verfasst: Donnerstag 21. August 2014, 14:16
von jens
Ist doch das selbe verhalten wie ein str.replace() oder?