J'ai deux extraits de code qui essaie de convertir une liste de flotteurs en une liste Vector3 ou Vector2. L'idée est de prendre 2/3 éléments à la fois de la liste et de les combiner comme un vecteur. Le résultat final est une séquence de vecteurs.
let rec vec3Seq floatList = seq { match floatList with | x::y::z::tail -> yield Vector3(x,y,z) yield! vec3Seq tail | [] -> () | _ -> failwith "float array not multiple of 3?" } let rec vec2Seq floatList = seq { match floatList with | x::y::tail -> yield Vector2(x,y) yield! vec2Seq tail | [] -> () | _ -> failwith "float array not multiple of 2?" }
4 Réponses :
Comme Rex commenté, si vous le souhaitez que pour deux cas, vous n'aurez probablement aucun problème si vous laissez le code tel qu'il est. Toutefois, si vous souhaitez extraire un modèle commun, vous pouvez écrire une fonction qui scindre une liste dans la sous-liste d'une longueur spécifiée (2 ou 3 ou tout autre numéro). Une fois que vous faites cela, vous n'utiliserez que La fonction de la liste de fractionnement n'est pas disponible dans le F # Bibliothèque (autant que je puisse dire), vous devrez donc la mettre en œuvre vous-même. Il peut être fait à peu près à celui-ci: p> MAINTENANT, vous pouvez utiliser cette fonction pour implémenter vos deux conversions telles que ceci: p> Cela donnera un avertissement, car nous utilisons un modèle incomplet qui s'attend à ce que les listes retournées soient de longueur 2 ou 3 respectivement, mais c'est une attente correcte, le code fonctionnera donc bien. J'utilise également une brève version de Séquence Expression em> le mapper code> pour activer chaque liste de la longueur spécifiée dans
vecteur code>.
-> code> fait la même chose que
rendez code>, mais il ne peut être utilisé que dans des cas simples comme celui-ci. p> p>
Voici une approche. Je ne sais pas à quel point cela plus simple est vraiment, mais cela abstrait une partie de la logique répétée.
let rec mkSeq (|P|_|) x = seq { match x with | P(p,tail) -> yield p yield! mkSeq (|P|_|) tail | [] -> () | _ -> failwith "List length mismatch" } let vec3Seq = mkSeq (function | x::y::z::tail -> Some(Vector3(x,y,z), tail) | _ -> None)
Plus je regarde ça, plus je l'aime.
Bel usage d'un motif actif partiel.
Ceci est incroyablement élégant. Je n'ai jamais imaginé passer un modèle actif dans une fonction. Impressionnant. Merci pour ça.
Honnêtement, ce que vous avez à peu près bien que possible, bien que vous puissiez pouvoir faire un peu plus compact en utilisant ceci: maintenant le processus de rupture de votre Les listes sont déplacées dans ses propres fonctions génériques "Prendre" et "Split", c'est beaucoup plus facile à mapper sur le type souhaité. p> p>
Ceci est simular à la solution de KVB mais n'utilise pas de modèle actif partiel.
let rec listToSeq convert (list:list<_>) = seq { if not(List.isEmpty list) then let list, vec = convert list yield vec yield! listToSeq convert list } let vec2Seq = listToSeq (function | x::y::tail -> tail, Vector2(x,y) | _ -> failwith "float array not multiple of 2?") let vec3Seq = listToSeq (function | x::y::z::tail -> tail, Vector3(x,y,z) | _ -> failwith "float array not multiple of 3?")
semble assez propre pour moi, je ne pense pas que vous rencontrez un problème de maintenabilité
Vous pouvez écrire un code générique qui pourrait attraper n articles, puis utiliser une correspondance pour choisir
vector3 code> ou
vector2 code> (selon le cas), mais pourquoi? Les frais généraux seraient plus compliqués que ce que vous avez ici. Maintenant, si vous allez jusqu'à 12 ans, c'est une autre histoire ....