2010-05-09 6 views
1

J'ai plusieurs noms dans l'ordre alphabétique avec plusieurs occurrences du même nom dans l'ordre alphabétique de sorte que les noms sont tous regroupés. A côté de chaque nom, après le coma, j'ai un rôle qui a été assigné, une paire par ligne, quelque chose comme nom-rôle ce qui est indiqué ci-dessousBesoin d'un algorithme pour regrouper plusieurs paramètres d'une personne sous le nom de personnes

nom1, Rôle1
nom1, Role2
nom1, role3
nom1, role8
nom2, role8
nom2, role2
nom2, role4
NAME3, rôle1
nom4, role5
nom4 role1
...
..
.

Je cherche un algorithme pour prendre le fichier .csv ci-dessus comme entrée créer le fichier d'une sortie dans le format suivant

nom1, rôle1, rôle2, role3, role8
nom2, role8, rôle2 , role4
NAME3, rôle1
nom4, role5 role1
...
..
. Donc, fondamentalement, je veux que chaque nom apparaisse une seule fois, puis les rôles à imprimer au format csv à côté des noms de tous les noms et rôles dans le fichier d'entrée.

L'algorithme doit être indépendant du langage. J'apprécierais s'il n'utilise pas les principes de POO :-) Je suis un débutant.

+0

La POO est interdite. Les structures de données peuvent-elles être utilisées? – kennytm

+0

Bien que demandé différemment, cela se termine par presque une copie de: http://stackoverflow.com/questions/2748156/awk-sed-bash-to-merge-concatenate-data/2748870#2748870 –

+0

@Kenny - Aucune structure de données . Je dois être une telle douleur, non? @Jerry - Merci pour le lien, Jerry. – QuickMist

Répondre

4

De toute évidence, il y a quelques bogues de mise en forme, mais cela vous aidera à démarrer.

var lastName = ""; 

do{ 
    var name = readName(); 
    var role = readRole(); 
    if(lastName!=name){ 
    print("\n"+name+","); 
    lastName = name; 
    } 
    print(role+","); 
}while(reader.isReady()); 
+0

Merci Stefan, appréciez votre solution, mais quand lastName sera-t-il mis à jour dans votre algorithme? – QuickMist

+1

J'ai corrigé le code de Stefan (j'espère que ça ne vous dérange pas) d'ajouter l'endroit où actualiser le contenu 'lastName'. –

+0

@Matthieu - Merci pour la clarification. – QuickMist

0

Ceci est facile à faire si votre langue a des tableaux associatifs: tableaux qui peuvent être indexés par quoi que ce soit (comme une chaîne) plutôt que de simples chiffres. Certaines langues les appellent "hashes", "maps" ou "dictionnaires". Par contre, si vous pouvez garantir que les noms sont regroupés comme dans vos données d'exemple, la solution de Stefan fonctionne plutôt bien.

0

Il est un peu dommage que vous a dit qu'il fallait être la langue agnostique parce que Python est assez bien qualifié pour cela:

import itertools 
def split(s): 
    return s.strip().split(',', 1) 
with open(filename, 'r') as f: 
    for name, lines in itertools.groupby(f, lambda s: split(s)[0]) 
    print name + ',' + ','.join(split(s)[1] for s in lines) 

Fondamentalement, l'appel groupby prend toutes les lignes consécutives avec le même nom et les groupe ensemble.

Maintenant que j'y pense, la réponse de Stefan est probablement plus efficace.

+0

Très cryptique. Je ne comprends pas très bien. Qu'est-ce que Lamda s :? – QuickMist

+1

'lambda s: split (s) [0]' est une fonction qui appelle 'split (s)', puis retourne le premier élément du tuple retourné - qui dans ce cas est le nom, la première chose sur la ligne. 'itertools.groupby' utilise cette fonction pour grouper les lignes par leur nom. Alors 'lambda s: split (s) [1]' renvoie la deuxième chose sur la ligne, le rôle, et cette ligne rejoint tous les rôles avec des virgules. (Je l'ai juste affiché comme une curiosité, ce n'est pas la réponse que vous cherchiez.) –

+0

Je ne connaissais pas le groupby, merci David! –

0

Voici une solution en Java:

Scanner sc = new Scanner (new File(fileName)); 
Map<String, List<String>> nameRoles = new HashMap<String, List<String>>(); 
while (sc.hasNextLine()) { 
    String line = sc.nextLine(); 
    String args[] = line.split (","); 
    if (nameRoles.containsKey(args[0]) { 
    nameRoles.get(args[0]).add(args[1]); 
    } else { 
    List<String> roles = new ArrayList<String>(); 
    roles.add(args[1]); 
    nameRoles.put(args[0], roles); 
    } 
} 

// then print it out 
for (String name : nameRoles.keySet()) { 
    List<String> roles = nameRoles.get(name); 
    System.out.print(name + ","); 
    for (String role : roles) { 
    System.out.print(role + ","); 
    } 
    System.out.println(); 
} 

Avec cette approche, vous pouvez travailler avec une entrée aléatoire comme:

nom1, Rôle1

NAME3, Rôle1

nom2 , role8

nom1, rôle2

nom2, Role2

nom4, role5

nom4 role1

+0

Merci pour la solution, mais je ne comprends pas ce que Map > nameRoles = new HashMap >(); veux dire. – QuickMist

+0

Aussi, si vous pouviez me dire la logique que vous avez suivie, ce serait très utile. – QuickMist

+0

Ils sont une implémentation spécifique de Java mais vous pouvez trouver cela dans presque tous les autres langages de programmation. La structure de données est semblable à ceci: l'image que vous avez une table avec 2 colonnes, où une colonne contient une clé unique, et un tableau de données dans l'autre colonne. Chaque fois que vous avez une nouvelle donnée comme name1 - role2. Vous trouvez le nom1 dans la clé de la colonne (en hachant, en boucle ...), puis vous sortez le tableau de données correspondant dans l'autre colonne. Ensuite, vous ajoutez role2 dans ce tableau de données – vodkhang

0

Ici, il est en C# en utilisant rien de fantaisie. Il devrait être auto-explicatif:

static void Main(string[] args) 
{ 
    using (StreamReader file = new StreamReader("input.txt")) 
    { 
     string prevName = ""; 
     while (!file.EndOfStream) 
     { 
      string line = file.ReadLine(); // read a line 

      string[] tokens = line.Split(','); // split the name and the parameter 

      string name = tokens[0]; // this is the name 
      string param = tokens[1]; // this is the parameter 

      if (name == prevName) // if the name is the same as the previous name we read, we add the current param to that name. This works right because the names are sorted. 
      { 
       Console.Write(param + " "); 
      } 
      else // otherwise, we are definitely done with the previous name, and have printed all of its parameters (due to the sorting). 
      { 
       if (prevName != "") // make sure we don't print an extra newline the first time around 
       { 
        Console.WriteLine(); 
       } 
       Console.Write(name + ": " + param + " "); // write the name followed by the first parameter. The output format can easily be tweaked to print commas. 
       prevName = name; // store the new name as the previous name. 
      } 
     } 
    } 
} 
+0

Merci pour cette solution. Celui-ci m'a aidé à comprendre l'algorithme que je devais utiliser, ce que je voulais depuis le début. C'est assez facile à comprendre et explicite. – QuickMist

Questions connexes