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

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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]

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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.
Das Leben ist wie ein Tennisball.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Oh, super Idee! Mal testen...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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:])]
Das Leben ist wie ein Tennisball.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Da has du natürlich Recht. Ein wenig Nachdenken vor dem Posten hätte wohl geholfen :oops:
Das Leben ist wie ein Tennisball.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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.
Das Leben ist wie ein Tennisball.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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 ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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()
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@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
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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()
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@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]
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Nagut... :evil:
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ob man das nicht eigentlich als Feature Request einreichen könnte? Also ein l=l.replace([2,3], "X") ?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Unter welchem Namen? `replace()` geht ja nicht, das gibt es schon und das hat für diese Argumente bereits eine Bedeutung.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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]

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
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?)
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

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 --- "

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@jens: Habe das schon verstanden, aber das finde ich sehr komisch. Ich hätte da etwas anderes erwartet.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Ist doch das selbe verhalten wie ein str.replace() oder?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten