Gibt es eine Möglichkeit, String in Haskell bei der letzten Vorkommen von gegebenem Zeichen in 2 Listen zu teilen? Zum Beispiel möchte ich die Liste "a b c d e" auf Leerzeichen in ("a b c d", "e") aufteilen. Vielen Dank für die Antworten.Haskell Split String beim letzten Auftreten
Antwort
Ich bin mir nicht sicher, warum die vorgeschlagenen Lösungen so kompliziert sind. Nur ein zwei Traversierungen benötigt:
splitLast :: Eq a => a -> [a] -> Either [a] ([a],[a])
splitLast c' = foldr go (Left [])
where
go c (Right (f,b)) = Right (c:f,b)
go c (Left s) | c' == c = Right ([],s)
| otherwise = Left (c:s)
Hinweis: Dies ist Gesamt und eindeutig sein Scheitern bedeutet. Wenn eine Aufteilung nicht möglich ist (da das angegebene Zeichen nicht in der Zeichenfolge enthalten ist), wird eine Left
mit der ursprünglichen Liste zurückgegeben.Andernfalls gibt es eine Right
mit den zwei Komponenten zurück.
Dies ist vielleicht die einfachste, die ich bisher gesehen habe, aber es führt tatsächlich zwei Durchgänge, eine Dekonstruktion der Eingabe und eine andere Konstruktion der Ausgabe. Es ist daher strenger als notwendig und langsamer für sehr lange Listen. Sie können dies beheben, aber das Risiko von Speicherlecks zu vermeiden könnte ein bisschen schwierig sein. – dfeuer
@dfeuer Danke für die Korrektur. Ich vergesse immer, dass die Struktur wieder aufgebaut werden muss. Die Alternative, die du erwähnst, wäre eine linke Falte? – Alec
Hrmmm ... Was ich dachte, wird nicht funktionieren. Ich denke, der einzige faule Weg ist, ein Stück anzusammeln und abzuwarten, ob es am Ende befestigt werden soll. – dfeuer
Es ist nicht schön, aber es funktioniert:
import Data.List
f :: Char -> String -> (String, String)
f char str = let n = findIndex (==char) (reverse str) in
case n of
Nothing -> (str, [])
Just n -> splitAt (length str - n -1) str
ich meine f 'e' "a b c d e" = ("a b c d ", "e")
, aber ich würde mich nicht, dass der Raum Hinter zuzuschneiden.
Könnte es auch machen 'a -> [a] -> ([a], [a])', nein? –
@chris martin Sicher, tun Sie, wie Sie möchten, ich wollte nur klar machen, wie Sie diese Funktion in diesem Kontext verwenden, indem Sie diese Typensignatur bereitstellen. – suffi
kann ich die folgende Lösung vor:
splitLast list elem = (reverse $ snd reversedSplit, reverse $ fst reversedSplit)
where
reversedSplit = span (/= elem) $ reverse list
wahrscheinlich nicht die schnellste (zwei unnötige umkehrt), aber Ich mag es Einfachheit ist.
Wenn Sie auf Entfernen der Raum bestehen wir aufteilen, können Sie gehen für:
import qualified Data.List as List
splitLast list elem = splitAt (last $ List.elemIndices elem list) list
jedoch diese Version, dass davon ausgegangen, mindestens ein Element sein, das Muster entspricht. Wenn Sie diese Annahme nicht mögen, wird der Code etwas länger (aber keine Doppel Umkehrungen hier):
import qualified Data.List as List
splitLast list elem = splitAt index list where
index = if null indices then 0 else last indices
indices = List.elemIndices elem list
Natürlich Wahl zu Beginn der Spaltung ist willkürlich und wahrscheinlich am Ende Aufspaltung wäre intuitiv für Sie - dann können Sie einfach 0
durch length list
ersetzen Ich würde mit mehr Musterabgleich gehen.
import Data.List
splitLast = contract . words
where contract [] = ("", "")
contract [x] = (x, "")
contract [x,y] = (x, y)
contract (x:y:rest) = contract $ intercalate " " [x,y] : rest
Für lange Listen verbinden wir einfach die ersten beiden Strings mit einem Leerzeichen und versuchen die kürzere Liste erneut. Sobald die Länge auf 2 reduziert ist, geben wir nur das Saitenpaar zurück.
(x, "")
schien eine vernünftige Wahl für Strings ohne Leerzeichen, aber ich nehme an, Sie könnten ("", x)
stattdessen zurückgeben.
Es ist nicht klar, dass ("", "")
die beste Wahl für leere Zeichenfolgen ist, aber es scheint eine sinnvolle Alternative zu einem Fehler zu sein oder den Rückgabetyp zu etwas wie Maybe (String, String)
zu ändern.
Meine Idee ist es, bei jedem Auftreten zu teilen und dann die ersten Teile vom letzten Teil zu trennen.
Spitz:
import Control.Arrow -- (&&&)
import Data.List -- intercalate
import Data.List.Split -- splitOn
breakOnLast :: Eq a => a -> [a] -> ([a], [a])
breakOnLast x = (intercalate x . init &&& last) . splitOn x
Punkt frei:
liftA2 (.) ((&&& last) . (. init) . intercalate) splitOn
(.) <$> ((&&&) <$> ((.) <$> pure init <*> intercalate) <*> pure last) <*> splitOn
- 1. Split Saite beim ersten Auftreten
- 2. Split-String nur beim ersten Auftreten des angegebenen Zeichens
- 3. Split-String von letzten Separator
- 4. Split-String in neuestem Auftreten des Teils
- 5. Haskell Mehrdeutiges Auftreten (+) beim Definieren eines Vektors
- 6. String Split von gegeben letzten spezifischen Schlüsselwort
- 7. String Split auf letzten Komma in R
- 8. C# -Syntax - Entferne letztes Auftreten von ';' In String von Split
- 9. Split bei einzelnen Separator Auftreten
- 10. Haskell Filter/split Liste
- 11. Split-String in Sätze
- 12. Split String von den letzten zwei Zeichen in r
- 13. Split-String und dann alle Artikel ohne die letzten
- 14. Haskell: String Splitting. Learning algo
- 15. String Manipulation in Haskell
- 16. Wie Regex bis zum letzten Auftreten?
- 17. Fehler beim ersten Auftreten
- 18. Regex beim ersten Auftreten von # STRING # innerhalb der Regex
- 19. Split-String in Google-Blättern
- 20. Finden Auftreten von String generate_series
- 21. String Ersetzen in Auftreten java
- 22. Java Split String zu Array
- 23. Mehrdeutige Auftreten Kompilierungsfehler von benutzerdefinierten Datentypen in Haskell
- 24. Split string und exclude last split
- 25. Split eine Arraylist in Java in zwei Teil-Listen beim Auftreten eines speziellen Charakter
- 26. Zeichenkette nach dem letzten Auftreten eines Zeichens entfernen
- 27. Dart - Split String von RegEx
- 28. Python Split String
- 29. String Split Frage mit "*"
- 30. Split CSV String
'breakLastSpace str = (reverse (drop 1 y), umgekehrtes x) where (x, y) = break (== '') $ reverse str ist eine relativ naive Implementierung. –
Beachten Sie auch, dass Sie Ihre Zeichenfolge auf Leerzeichen durch die Funktion 'words' teilen können. – suffi
Beachten Sie, dass' text' 'breakOnEnd :: Text -> Text -> (Text, Text)' so dass ' T.breakOnEnd "" "abcde" 'gibt das gewünschte Ergebnis (" abcd "," e ")'. – Michael