9
votes

Comment puis-je intersecter deux listes dans OCAML?

Lorsque j'ai deux listes dans OCAML, par exemple

[3; 5; 7]


0 commentaires

7 Réponses :


4
votes

Je ne connais pas OCAML (Syntax-Wise), mais vous pouvez généralement le faire de deux manières:

  1. Si votre langue est prise en charge d'un ensemble de données de données de jeu, convertissez les deux listes en ensembles et utilisez l'opération de l'intersection SET.

  2. plus généralement: triez les deux listes, puis numérisez les listes de tri, ce qui facilite la recherche des duplicats beaucoup plus efficaces. Vous prenez n journal (n) pour trier et trouver les doublons en temps linéaire.


1 commentaires

OCAML ont défini fonctionnement: Caml.inria.fr/ PUB / DOCS / Manual-OCAML / LIBREF / SET.S.S.HTML Notez que la solution BOT équivalente à terme de complexité (avec OCAML SET).



8
votes

Comme Franck et Rémi ont dit, convertir vos listes en ensembles (à partir de STDLIB MODULE SET) COÛTS N LOG (N), puis définit une implémentation linéaire de l'intersection. Franck a également mentionné l'alternative équivalente pour trier les listes, puis les traverser de manière synchronisée. Celles-ci sont à peu près les mêmes (et d'ailleurs, dans les deux cas, vous devez être capable de fournir une commande totale sur les éléments de vos listes).

Si les intersections sont une partie importante de votre algorithme et que vous souhaitiez qu'ils soient plus rapides dans le cas de deux ensembles d'éléments qui ne sont que légèrement différents, vous devez passer à une structure , telle que Patricia arbres. Voir fichiers pt * dans http: //www.lri .fr / ~ Filliatr / ftp / ocaml / ds / .

Si vous avez besoin d'intersection pour être rapide dans tous les cas, vous avez la possibilité d'utiliser des arbres de Patricia comportant un hachage. Le reconscription hachage aide à reconnaître des sous-arbres structurellement identiques et à aider à créer des caches efficaces pour les opérations précédentes en faisant comparaison bon marché.

Les arbres Patricia ne peuvent pas utiliser de type arbitraire sous forme de clé (généralement ils sont présentés avec des clés d'INTS). Mais vous pouvez parfois contourner cette limitation en numérotant à la création de chaque valeur que vous souhaitez utiliser comme clé.


0 commentaires

5
votes

Mon ocaml n'est pas le meilleur, mais j'ai piraté cette fonction ensemble, qui intersectez les listes triées: xxx

qui doit fonctionner dans O (n + m). Fondamentalement, il vérifie le premier élément de chaque liste. S'ils sont égaux, il stocke le résultat de l'appel récursif à leurs queues, puis vérifie si la tête du résultat stocké est égale à la tête des listes. Si ce n'est pas le cas, il l'insère, sinon c'est un duplicata et qu'il l'ignore.

S'ils ne sont pas égaux, cela avance seulement celui qui est plus petit.


1 commentaires

La fonction me semble bien. J'ai la plus petite des remarques cependant. Si vous écrivez | H3 :: T3 comme L -> H1 :: L au lieu de | H3 :: T3 -> H1 ::( H3 :: T3) , vous pouvez enregistrer le compilateur l'allocation d'une nouvelle cellule de client pour créer une nouvelle liste identique à celle qu'elle a déjà. Le compilateur pourrait faire cette optimisation elle-même, mais ce n'est probablement pas.



3
votes

Comme @frank suggéré, vous pouvez utiliser des ensembles pour résoudre ce problème, bien que ce ne soit pas la meilleure réponse possible, mais voici une liste de codes courts démontrant comment cela pourrait être atteint dans OCAML:

3
5
7
- : unit = ()


0 commentaires

1
votes

Si vos listes ne contiennent que des entiers d'une taille limitée, il existe également une solution dans O (N):

1.) Créez une gamme de booléens de la taille de votre plus grande valeur entière plus 1 dans vos listes d'origine (par exemple dans votre exemple '9 + 1'); Définissez tous les champs sur false;

let m = array.create 10 false

-> [| faux; faux; faux; faux; faux; faux; faux; faux; faux; faux |]

2.) Itérate sur la première liste: pour chaque élément que vous rencontrez, définissez le booléen avec le décalage respectif sur «vrai»; Dans votre exemple, cela céderait

list.iter (amusant x -> m. (x) <- vrai) E1

-> [| faux; faux; faux; vrai; vrai; vrai; vrai; vrai; faux; faux |]

3.) Filtrez sur la deuxième liste, conservant uniquement les éléments dont le champ correspondant dans la matrice est vrai

list.filter (fun x -> m. (x) = true) e2

-> [3; 5; 7]


0 commentaires

1
votes

Je ne pense pas que ma solution est O (n), mais elle est très courte et peut être intéressante pour les personnes qui ne sont pas limitées par des contraintes de complexité (comme cette réponse est l'un des premiers résultats de recherche pour "La liste des intersecteurs OCAML ")

Cette fonction renvoie true quand l'intersection n'est pas vide. En d'autres termes, il vérifie si deux listes d'éléments de partage, si oui, true, sinon faux. xxx

très similaire, cette fonction renvoie l'intersection réelle. < Pré> xxx

N'hésitez pas à me corriger si mon Soluton n'est pas correct. Il devrait être polymorphe, car x et y peuvent être n'importe quel type pouvant être comparé.


0 commentaires

0
votes

En tant qu'affipe précédente a déclaré, il s'agit de l'un des premiers résultats de recherche pour «Intersect listes de OCAML», donc je pose une réponse simple ici qui ne répond pas aux préoccupations concernant la complexité.

    # let e1 = [3; 4; 5; 6; 7];;
    # let e2 = [1; 3; 5; 7; 9];;
    # List.filter (fun x -> List.mem x e1) e2;;
    - : int list = [3; 5; 7]
    # 


0 commentaires