2 votes

Haskell : faire une liste de listes à partir d'une seule chaîne de caractères

J'ai des données dans un fichier txt qui ressemble à ceci :

  [Just 3, Nothing, Just 1, Nothing] [Nothing, Nothing, Nothing, Nothing] [Nothing, Nothing, Just 4, Nothing] [Nothing, Just 3, Nothing, Nothing]

Ce dont j'ai besoin, c'est d'avoir une liste de listes contenant les valeurs ci-dessus sous forme d'entiers, par ex.

[[3,0,1,0],[0,0,0,0],....]

Et ainsi de suite. Avez-vous une idée de la façon de le faire correctement ? Je peux remplacer "nothing" par 0 et laisser tomber la partie "Just" mais cela restera une seule chaîne.

1voto

user2297560 Points 2678

La bonne façon de procéder est probablement d'utiliser une bibliothèque d'analyseur syntaxique telle que Text.Parsec . Ceci étant dit, voici une façon rapide et bricolée de le faire, qui n'est pas sans rappeler ce qu'un programmeur Python pourrait inventer. L'idée est de transformer la chaîne de caractères d'entrée en une forme que read sera analysé pour nous.

{-# LANGUAGE OverloadedStrings #-}

import Prelude hiding (null)
import Data.Text (snoc, pack, unpack, splitOn, strip, null)
import Data.Maybe (fromMaybe)
import System.IO

parse :: String -> [[Maybe Int]]
parse = map read . map unpack . map (flip snoc ']') . filter (not . null) . map strip . splitOn "]" . pack

main :: IO ()
main = do
  input <- readFile "myfile.txt"  -- input = "[Just 3, Nothing, Just 1, Nothing] [Nothing, Nothing, Nothing, Nothing] [Nothing, Nothing, Just 4, Nothing] [Nothing, Just 3, Nothing, Nothing]"
  putStrLn . show $ map (map (fromMaybe 0)) (parse input)

En parse fonctionne comme suit :

  • pack convertit un String en une valeur Text valeur
  • splitOn "]" fait exactement ce que vous pensez
  • map strip supprime les espaces en tête et en queue de page
  • filter (not . null) supprime les chaînes vides (il y en a une à la fin)
  • map (flip snoc ']') ajouter le caractère "]" à la fin de chaque chaîne de caractères
  • map unpack convertit chaque Text à une valeur String valeur
  • map read analyse chaque String en une valeur [Maybe Int]

0voto

Juste une version alternative qui utilise read :

import Data.List.Split (splitOn)
import Data.Maybe      (fromMaybe)

main :: IO ()
main = do
    s <- readFile "lists.txt"
    let xs = map (\s' -> map (fromMaybe 0) (read (s' ++ "]"))) . init . splitOn "]" $ s
    print xs

L'idée est simple : d'abord, le contenu du fichier est lu en tant que String et lié à s . Alors, s est analysé en une liste d'entiers ( [Int] ) qui est lié à xs . Pour ce faire, les mesures suivantes sont prises :

  1. splitOn "]" : divise la chaîne d'entrée s générer une liste de chaînes de caractères ( [String] ). Chaque élément manque le caractère ']' à la fin. Le dernier élément de cette liste est un indésirable. "\n" . La liste obtenue est la suivante :

    ["[Just 3, Nothing, Just 1, Nothing"," [Nothing, Nothing, Nothing, Nothing", ..., "\n"]
  2. init : supprime les " \n ".

  3. map (\s' -> map (fromMaybe 0) (read (s' ++ "]"))) : applique à chaque élément de la chaîne la fonction lambda ci-jointe, qui fait :

    1. read (s' ++ "]") : ajouter les éléments manquants ']' à la chaîne et l'analyse en une liste de Maybe s ( Num a => [Maybe a] ). Notez que nous n'avons pas besoin de spécifier explicitement un type pour read car GHC peut le déduire de l'utilisation de l'option fromMaybe 0 (voir ci-dessous).
    2. map (fromMaybe 0) : appliquer la fonction fromMaybe 0 sur chaque élément de la liste, qui renvoie v quand Just v ; et 0 sinon.

De cette façon, vous read .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X