dire que j'ai une séquence de 100 éléments. Chaque 10ème élément Je souhaite une nouvelle liste des 10 éléments précédents. Dans ce cas, je finirai avec une liste de 10 sublistes. P>
seq.take (10) semble prometteur, comment puis-je l'appeler à plusieurs reprises pour renvoyer une liste de listes? p>
8 Réponses :
Ce n'est pas mauvais:
let splitEach n s = seq { let r = ResizeArray<_>() for x in s do r.Add(x) if r.Count = n then yield r.ToArray() r.Clear() if r.Count <> 0 then yield r.ToArray() } let s = splitEach 5 [1..17] for a in s do printfn "%A" a (* [|1; 2; 3; 4; 5|] [|6; 7; 8; 9; 10|] [|11; 12; 13; 14; 15|] [|16; 17|] *)
En optimisation mineure, vous pourriez passer n code> dans le constructeur de resizearray, pour définir la capacité initiale à ce que vous savez que cela aura besoin de tenir.
Je vais avec cette réponse parce que c'est le plus facile pour moi de comprendre.
Out du haut de ma tête:
let rec split size list = if List.length list < size then [list] else (list |> Seq.take size |> Seq.toList) :: (list |> Seq.skip size |> Seq.toList |> split size)
Un problème possible avec cette approche est que chaque morceau énumère la séquence du début (jusqu'à la fin du morceau), il existe donc environ N / 2 fois plus d'itération que nécessaire (pour une séquence de longueur n).
Devez-vous convertir la séquence en une liste avant d'appeler cette fonction?
Je pense que la solution de Brian est probablement l'option simple la plus raisonnable. Un probelm avec des séquences est qu'ils ne peuvent pas être facilement traités avec la correspondance habituelle des motifs (comme des listes fonctionnelles). Une option pour éviter que ce soit d'utiliser Une autre option consiste à définir un constructeur de calcul pour travailler avec lazyliste code> de F # Powerpack.
ienumerator code> type. J'ai récemment écrit quelque chose comme ça récemment - Vous pouvez l'obtenir ici . Ensuite, vous pouvez écrire quelque chose comme: P>
let splitEach chunkSize (s:seq<_>) =
Enumerator.toSeq (fun () ->
let en = s.GetEnumerator()
let rec loop n acc = iter {
let! item = en
match item with
| Some(item) when n = 1 ->
yield item::acc |> List.rev
yield! loop chunkSize []
| Some(item) ->
yield! loop (n - 1) (item::acc)
| None -> yield acc |> List.rev }
loop chunkSize [] )
J'ai une évolution de trois solutions. Aucun d'entre eux ne conserve la commande des éléments d'entrée, espérons-le, d'accord.
Ma première solution est assez laide (utilisation de cellules refaf): p>
each [] [] 0 |> List.rev |> List.map List.rev
Peut-être que cette simple implémentation pure pourrait être utile: par exemple: p>
En cas de doute, utilisez le pli.
let split n = let one, append, empty = Seq.singleton, Seq.append, Seq.empty Seq.fold (fun (m, cur, acc) x -> if m = n then (1, one x, append acc (one cur)) else (m+1, append cur (one x), acc)) (0, empty, empty) >> fun (_, cur, acc) -> append acc (one cur)
J'ai trouvé que cela soit facilement le plus rapide:
let windowChunk n xs = let range = [0 .. Seq.length xs] Seq.windowed n xs |> Seq.zip range |> Seq.filter (fun d -> (fst d) % n = 0) |> Seq.map(fun x -> (snd x))
maintenant il y a seq.chunkbysize code> disponible: