2010-12-02 6 views
1

J'ai eu récemment d'écrire l'algorithme suivant:algorithme: Sélection d'éléments communs d'une collection

Compte tenu d'un groupe de balises, et un groupe de messages de blog, où un billet de blog peut contenir zéro à -plusieurs étiquettes, renvoient les étiquettes communes à tous les articles.

Cette comparaison est fait en mémoire - l'accès soit collection ne pas la cause d'un voyage à travers le réseau (par exemple, à une base de données, etc.).

En outre, la collection Tags ne contient pas de référence à BlogPosts qui la contient. BlogPosts ont une collection de Tags qu'ils contiennent.

Voici ma mise en œuvre. Cela fonctionne très bien, mais je suis curieux de savoir s'il y avait une meilleure façon de l'implémenter.

Mon implémentation est dans Actionscript, mais je suis plus curieux du point de vue des algorithmes, donc les exemples dans n'importe quelle langue sont bons. (Mais si je ne connais pas la langue, je peux vous demander de clarifier certains aspects)

Tous les exemples d'améliorations seraient grandement reçus.

private function getCommonTags(blogPosts:Vector.<BlogPost>):Vector.<Tag> 
    { 
     var commonTags:Vector.<Tag> = new Vector.<Tag>(); 
     if (!blogPosts || blogPosts.length == 0) 
      return commonTags; 

     var blogPost:BlogPost = blogPosts[0]; 
     if (!blogPost.tags || blogPost.tags.length == 0) 
      return commonTags; 

     commonTags = Vector.<Tag>(blogPosts[0].tags); 

     for each (var blogPost:BlogPost in blogPosts) 
     { 
      if (!blogPost.tags || blogPost.tags.length == 0 || commonTags.length == 0) 
       // Updated to fix bug mentioned below 
       // Optomized exit - there are no common tags 
       return new Vector.<Tag>(); 

      for each (var tag:Tag in commonTags) 
      { 
       if (!blogPost.containsTagId(tag.id)) 
       { 
        commonTags.splice(commonTags.indexOf(tag),1); 
       } 
      } 
     } 
     return commonTags; 
    } 
+2

Je ne sais pas Actionscript, mais ce code fonctionnera plus vite si vous pouvez commander à peu de frais le blogposts par blogPost.tags.length. Aussi je pense qu'il y a un bug quand le premier post a 2 tags et le second 0, il va retourner les 2 tags du premier post. –

+0

@ krusty.ar Merci! Tri par le nombre de tags est une excellente idée. Je pense que le bogue que vous mentionnez provient d'une mauvaise modification de la variable en mon nom - j'ai édité le code, faites le moi savoir si vous voyez toujours le bogue (je ne le fais pas). –

+1

Ok, supposons que blogPosts [0] .tags.lenght == 2 et blogPosts [0] .tags.lenght == 0, le premier passage de chaque boucle comparera les 2 tags du premier post avec les 2 tags de le premier post, qui sont identiques, donc commonTags.lenght == 2, dans le second passage de la boucle, blogPost.tags.length == 0, donc la "sortie optimisée" est utilisée, mais toujours commonTags.lenght == 2 , donc vous renvoyez les balises du premier post, dont le second post n'a pas, la version correcte serait quelque chose comme le retour du nouveau vecteur. (); –

Répondre

1

Eh bien, vous avez juste besoin d'un algorithme efficace pour calculer l'intersection de deux ensembles parce que vous pouvez simplement appeler à plusieurs reprises l'algorithme pour plus de deux ensembles.

Un algorithme rapide consiste à ajouter les éléments du premier ensemble à une table de hachage, puis à parcourir le second ensemble en vérifiant la table de hachage pour voir si elle est présente; Si c'est le cas, ajoutez-le à la liste des éléments à retourner dans l'intersection.

0

Je peux énoncer ce programme dans une phrase en anglais: «Renvoyer toutes les étiquettes qui se produisent uniformément parmi les messages."

Donner le nom all_tags à la liste des balises et post_tags à la liste des balises associées à des postes, je peux dire la même chose avec cette phrase dans le J programming language

all_tags #~ (#=+/) all_tags e.&>"_ 0 post_tags 

En regardant cette en détail:

  • #~ signifie "copie où"

  • (# = +/) signifie "décompte est égal à la somme"

  • e. signifie "existe dans"

  • &>"_ 0 modifie e. si l'ensemble de all_tags est comparée à chacune des étiquettes-ensembles dans post_tags

Si nous voulons faire de ce programme un programme qui prend deux arguments, plutôt qu'un programme spécifique à ces listes, le programme correspondant pourrait être:

common_to=: [ #~ [:(#=+/) [ e.&>"_ 0 ] 

L'exécution de ce programme avec les mêmes noms de données ressemblerait à ceci:

all_tags common_to post_tags 

Il semble intéressant de noter que nous ne pas vraiment besoin de la liste complète des balises, comme cela peut être dérivé. (Le calcul est ~. ; post_tags.) Cela signifie que nous pourrions écrire le programme pour prendre un seul argument. Mais puisque le problème suppose que nous avons déjà la liste all_tags calculée, il n'est pas nécessaire de le calculer à nouveau.

Questions connexes