Seite 1 von 2

Mississippi

Verfasst: Freitag 6. November 2009, 19:18
von hendrikS
In Haskell gibt es eine Funktion group, mit folgendem Effekt:
"Mississippi" => ['M', 'i', 'ss', 'i', 'ss', 'i', 'pp', 'i']
Habs mal in py nachgebaut. Vielleicht kanns jemand gebrauchen. Interessieren würde mich, ob man das auch mit einer Regexp schaffen kann. Habs versucht. Leider ohne Erfolg.

Code: Alles auswählen

def group(s):
    o = list()
    t = list(s[0])
    for c in s[1:]:
        if c == t[0]:
            t.append(c)
        else:
            o.append(''.join(t))
            t = list(c)
    return o + [''.join(t)]

Verfasst: Freitag 6. November 2009, 19:27
von rayo
Hi

Das kannst du auch mit itertools.groupby lösen:

Code: Alles auswählen

import itertools

s = "Mississippi"
print list(key*len(list(group)) for key,group in itertools.groupby(s))
Gruss

*edit* Gerolds Lösung ist definitiv schöner ... so weit hab ich wieder mal nicht gedacht.

Verfasst: Freitag 6. November 2009, 19:31
von gerold
Hallo!

Ich mag solche Ein-/Zweizeiler eigentlich nicht, aber ausnahmsweise... :-)

Code: Alles auswählen

>>> import itertools
>>> [ "".join(value) for key, value in itertools.groupby("Mississippi") ]
['M', 'i', 'ss', 'i', 'ss', 'i', 'pp', 'i']
>>>

mfg
Gerold
:-)


Edit: Ohhh, zu spät. ;-)

Verfasst: Freitag 6. November 2009, 19:34
von ms4py
Hier eine Lösung mit ``itertools``, die nicht ganz so magisch ist:

Code: Alles auswählen

from itertools import tee, izip
def group2(s):
    a, b = tee(s)
    b.next()
    o = [s[0]]
    i = 0
    for a0, b1 in izip(a, b):
        if a0 == b1:
            o[i] += b1
        else:
            o.append(b1)
            i += 1
    return o
Geht aber bestimmt noch besser.

Edit: OK, geht deutlich besser ^^
Als LC find ich das am besten, das mit list und * ist das auch nicht so elegant.

Verfasst: Freitag 6. November 2009, 19:51
von Defnull
Jup, das geht auch mit re

Code: Alles auswählen

>>> [m[0] for m in re.findall('((?P<char>.)(?P=char)*)','Mississippi')]
['M', 'i', 'ss', 'i', 'ss', 'i', 'pp', 'i']

Verfasst: Freitag 6. November 2009, 20:35
von gerold
Ich habe noch einen... diesmal ganz ohne Magie. :-) Ziemlich ähnlich der Lösung von hendrikS.

Code: Alles auswählen

dest_list = []
prev_char = None
for char in "Mississippi":
    if char == prev_char:
        dest_list[-1] += char
    else:
        dest_list.append(char)
    prev_char = char
print dest_list
lg
Gerold
:-)

PS: @Defnull: Tolle Lösung! 8)

Verfasst: Freitag 6. November 2009, 20:56
von hendrikS
wow. Jede menge Alternativlösungen.
Wenn ich gewußt hätte, daß es groupby gibt, hätte ichs vielleicht auch so gemacht.
Zur RegexpLösung. Erst habe ich gedacht, daß ist uneffizient. Beim zweiten Hinsehen finde ich es doch ziemlich smart.

Verfasst: Freitag 6. November 2009, 21:18
von pillmuncher
Ähnlich wie Gerolds Lösung:

Code: Alles auswählen

def group(cs):
    def groups(a, b):
        if b in a[-1]:
            a[-1] += b
        else:
            a += b
        return a
    return reduce(groups, cs[1:], [cs[:1]])

Verfasst: Freitag 6. November 2009, 22:36
von gerold
Hallo!

Nur mal kurz darüber nachgedacht...

Wir amüsieren uns hier köstlich mit diesen Quellcode-Abschnitten! :D
Aber stellt euch mal vor, ihr zeigt diesen Thread euren Freunden/Eltern/Verwanden...
Was sind wir wohl in deren Augen? :mrgreen:

lg
Gerold
:-)

Verfasst: Freitag 6. November 2009, 22:41
von numerix
gerold hat geschrieben:Wir amüsieren uns hier köstlich mit diesen Quellcode-Abschnitten! :D
Aber stellt euch mal vor, ihr zeigt diesen Thread euren Freunden/Eltern/Verwanden...
Was sind wir wohl in deren Augen? :mrgreen:
So etwas KANN man nicht zeigen, wenn man es im "echten Leben" auch mit "normalen" Menschen zu tun hat. Ansonsten setzt man sich der Gefahr einer Zwangseinweisung aus ...

Verfasst: Freitag 6. November 2009, 22:45
von pillmuncher
Noch einer, diesmal lazy:

Code: Alles auswählen

def _group(s, *ss):
    for c in ss:
        if c in s:
            s += c
        else:
            yield s
            s = c
    yield s

def group(cs):
    if cs == '':
        return iter('')
    return _group(*cs)

Verfasst: Freitag 6. November 2009, 22:56
von pillmuncher
numerix hat geschrieben:So etwas KANN man nicht zeigen, wenn man es im "echten Leben" auch mit "normalen" Menschen zu tun hat. Ansonsten setzt man sich der Gefahr einer Zwangseinweisung aus ...
Ich fand es immer schon ziemlich punkig, ein Nerd zu sein. :twisted:

Gruß,
Mick.

Verfasst: Freitag 6. November 2009, 23:01
von gerold
pillmuncher hat geschrieben:Noch einer, diesmal lazy:

Code: Alles auswählen

def _group(s, *ss):
    ...
def group(cs):
    ...
    return _group(*cs)
Hallo!

Dieses Beispiel nehmen wir jetzt um Python-Anfängern die Übergabe von Parametern zu erklären. ;-)

mfg
Gerold
:-)

Verfasst: Freitag 6. November 2009, 23:03
von Leonidas
gerold hat geschrieben:Wir amüsieren uns hier köstlich mit diesen Quellcode-Abschnitten! :D
Aber stellt euch mal vor, ihr zeigt diesen Thread euren Freunden/Eltern/Verwanden...
Was sind wir wohl in deren Augen? :mrgreen:
Wenn wir schon blödeln, dann steuere ich eine Scheme-Lösung bei. Wäre gespannt was man mit Factor zaubern könnte :)

Verfasst: Freitag 6. November 2009, 23:12
von gerold
Hallo!

Weiß jemand, wie das in Cython http://www.cython.org/ aussehen könnte? Ich interessiere mich dafür, da ich vielleicht demnächst ein paar Codeteile (nicht zwischenspeicherbare Rabattberechnungen) meines Onlineshops hoch optimieren muss.

lg
Gerold
:-)

Verfasst: Freitag 6. November 2009, 23:33
von hendrikS
gerold hat geschrieben: Was sind wir wohl in deren Augen? :mrgreen:
Bestimmt nicht so schlimm wie Du denkst. Jeder hat so seinen Spleen.

Scheme:
Die vielen Klammern haben mich immer davon abgehalten das mal zu probieren.

Und nicht zuletzt:
Gerolds nonmagic Version ist die effizienteste der Varianten.

Verfasst: Samstag 7. November 2009, 00:46
von pillmuncher
Leonidas hat geschrieben:Wenn wir schon blödeln, dann steuere ich eine Scheme-Lösung bei. Wäre gespannt was man mit Factor zaubern könnte :)
Factor kann ich nicht, aber Prolog:

Code: Alles auswählen

group(String, Groups) :-
    string_to_list(String, [C|Cs]),
    group(Cs, [C], Groups).

group([C|Cs], [C|Group], Groups) :-
    !,
    group(Cs, [C,C|Group], Groups).
group([C|Cs], Group, [String|Groups]) :-
    group(Cs, [C], Groups),
    string_to_list(String, Group).
group([], Group, [String]) :-
    string_to_list(String, Group).

Code: Alles auswählen

?- group("mississippi",G).
G = ["m", "i", "ss", "i", "ss", "i", "pp", "i"].
Da sieht man auch, wo ich das def _group(s, *ss): herhab ;-)

Verfasst: Montag 9. November 2009, 08:46
von ms4py
Hab meine Lösung nochmal überarbeitet^^

Code: Alles auswählen

from itertools import tee, izip

def group(s):
    a, b = tee(s)
    output = list()
    output.append(b.next())
    for prev_char, char in izip(a, b):
        if prev_char == char:
            output[-1] += char
        else:
            output.append(char)
    return output
Prolog weckt düstere Erinnerungen... Konnte das noch nie leiden ;)

Verfasst: Montag 9. November 2009, 16:14
von pillmuncher
ice2k3 hat geschrieben:

Code: Alles auswählen

    a, b = tee(s)
    output = list()
    output.append(b.next())
Das b.next() ist eine gute Idee:

Code: Alles auswählen

def group(cs):
    cs = iter(cs)
    s = cs.next()
    for c in cs:
        if c in s:
            s += c
        else:
            yield s
            s = c
    yield s
ice2k3 hat geschrieben:Prolog weckt düstere Erinnerungen... Konnte das noch nie leiden ;)
Juhuu! Ein Sprachenkrieg ;) Ich mochte Prolog schon immer, hatte auch nie irgendwelche Verständnis-Probleme (anders als bei Haskell :roll: ). Irgendwie scheint es der Verdrahtung meines Gehirns zu entsprechen. Und von Differenzlisten hab ich schon geträumt:

Code: Alles auswählen

?- asserta(append_dl(A - B, B - C, A - C)).
true.

?- append_dl([1,2,3|X] - X, [4,5,6|Y] - Y, Z - []).
X = [4, 5, 6],
Y = [],
Z = [1, 2, 3, 4, 5, 6] .
Gruß,
Mick.

Verfasst: Montag 9. November 2009, 21:50
von Nocta
Fehlt nicht noch was rekursives?

Code: Alles auswählen

def group(s, res=[], i=0, j=1):
    if i >= len(s)-1:
        return res + [s[i]*j]
    if s[i] == s[i+1]:
        return group(s, res, i+1, j+1)
    else:
        return group(s, res + [s[i]*j], i+1)
Das würde ich zwar nicht als elegant bezeichnen aber darum poste ich's weil mir gerade kein guter rekursiver Weg einfällt und irgendjemand hier soll ihn mir offenbaren :)
(Ist zwar fast schon peinlich, aber ich bin hier ja anonym :p)