J'ai gratté ma tête sur ce problème pendant un moment maintenant. J'essaie essentiellement de générer une hiérarchie des arbres à partir d'un ensemble de données CSV. Les données CSV ne sont pas nécessairement commandées. Ceci est comme quelque chose comme suit:
CSVParser csv = new CSVParser(content); String[] line; while((line = csv.readLine()) != null ) { ... }
6 Réponses :
basé sur la manière dont ce problème est posé, je ferais ce qui suit: p>
Est-ce que cela aide? P>
L'idée de base n'est pas difficile: groupe par le premier enregistrement, puis par le deuxième enregistrement, etc. Jusqu'à ce que vous obtenez quelque chose comme ceci:
// builds tree and returns a list of root nodes // list_of_tuples: a list of tuples read from your csv // curr_position: used to keep track of recursive calls // number_of_records: assuming each csv row has n records and then m values, number_of_records equals n function build_tree(list_of_tuples, curr_position, number_of_records) { // check if we have already reached the "values" (which shouldn't get converted into trees) if (curr_position == number_of_records) { return list of nodes, each containing a "value" (i.e. everything from position number_of_records on) } grouped = group tuples in list_of_tuples that have the same value in position curr_position, and store these groups indexed by such common value unique_values = get unique values in curr_position list_of_nodes = empty list // create the nodes and (recursively) their children for each val in unique_values { the_node = create tree node containing val the_children = build_tree(grouped[val], curr_position+1, number_of_records) the_node.set_children(the_children) list_of_nodes.append(the_node) } return list_of_nodes } // in your example, this returns a node with "A" and a node with "B" // third parameter is 2 because you have 2 "records" build_tree(list_parsed_from_csv, 0, 2)
Merci pour la pseudo pensée.
@Andez Désolé pour aucun vrai code Java, je pensais juste qu'un croquis serait plus approprié à ce stade afin de se concentrer sur l'algorithme. Notez que c'est la seule solution jusqu'à présent qui gère un nombre arbitraire de niveaux d'enregistrements. Si vous souhaitez traduire le code en Java (ou quiconque souhaite poster une réponse Java en fonction de ce que j'ai posté) Je serai heureux d'aider.
Si vous savez que vous n'aurez que deux niveaux de lorsque vous lisez une nouvelle ligne, vous regardez dans le Carte extérieure pour vérifier si cette valeur pour Vérifiez que la carte interne soit Une valeur pour ce puis lisez les valeurs et ajoutez-les à la liste. P> p> enregistrement code> s, j'utiliserais quelque chose comme
record1 code> existe déjà et sinon, créez une nouvelle carte intérieure vide code> pour cela. p>
record2 code> existe. Sinon, créez une nouvelle liste
code>. P>
C'est la chose, j'aurai plus de colonnes dépendantes des fichiers CSV que je traite. J'ai pris en compte les cartes d'abord. Merci anez
Voici la solution de base de base sous la forme de Junit (aucune assertion, cependant) simplifiée en utilisant Collections Google-Guava . Le code est explicite auto-explicite et au lieu de fichier IO, vous utilisez des bibliothèques CSV pour la lecture du CSV. Cela devrait vous donner l'idée de base.
import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import org.junit.Test; import com.google.common.base.Charsets; import com.google.common.base.Splitter; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.google.common.io.Files; public class MyTest { @Test public void test1() { List<String> rows = getAllDataRows(); Multimap<Records, Values> table = indexData(rows); printTree(table); } private void printTree(Multimap<Records, Values> table) { Set<String> alreadyPrintedRecord1s = Sets.newHashSet(); for (Records r : table.keySet()) { if (!alreadyPrintedRecord1s.contains(r.r1)) { System.err.println(r.r1); alreadyPrintedRecord1s.add(r.r1); } System.err.println("\t" + r.r2); Collection<Values> allValues = table.get(r); for (Values v : allValues) { System.err.println("\t\t" + v.v1 + " , " + v.v2); } } } private Multimap<Records, Values> indexData(List<String> lines) { Multimap<Records, Values> table = ArrayListMultimap.create(); for (String row : lines) { Iterable<String> split = Splitter.on(",").split(row); String[] data = Iterables.toArray(split, String.class); table.put(new Records(data[0], data[1]), new Values(data[2], data[3])); } return table; } private List<String> getAllDataRows() { List<String> lines = Collections.emptyList(); try { lines = Files.readLines(new File("C:/test.csv"), Charsets.US_ASCII); } catch (IOException e) { e.printStackTrace(); } lines.remove(0);// remove header return lines; } } public class Records { public final String r1, r2; public Records(final String r1, final String r2) { this.r1 = r1; this.r2 = r2; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((r1 == null) ? 0 : r1.hashCode()); result = prime * result + ((r2 == null) ? 0 : r2.hashCode()); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof Records)) { return false; } Records other = (Records) obj; if (r1 == null) { if (other.r1 != null) { return false; } } else if (!r1.equals(other.r1)) { return false; } if (r2 == null) { if (other.r2 != null) { return false; } } else if (!r2.equals(other.r2)) { return false; } return true; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Records1and2 [r1=").append(r1).append(", r2=").append(r2).append("]"); return builder.toString(); } } public class Values { public final String v1, v2; public Values(final String v1, final String v2) { this.v1 = v1; this.v2 = v2; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((v1 == null) ? 0 : v1.hashCode()); result = prime * result + ((v2 == null) ? 0 : v2.hashCode()); return result; } @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof Values)) { return false; } Values other = (Values) obj; if (v1 == null) { if (other.v1 != null) { return false; } } else if (!v1.equals(other.v1)) { return false; } if (v2 == null) { if (other.v2 != null) { return false; } } else if (!v2.equals(other.v2)) { return false; } return true; } @Override public String toString() { StringBuilder builder = new StringBuilder(); builder.append("Values1and2 [v1=").append(v1).append(", v2=").append(v2).append("]"); return builder.toString(); } }
Merci, a l'air intéressant. Va regarder dans ça.
J'ai récemment eu besoin de faire à peu près la même chose et a écrit Tree-Builder.com a > pour accomplir la tâche. La seule différence est que, comme vous avez votre CSV aménagée, les deux derniers paramètres seront parents et enfants au lieu de pairs. En outre, ma version n'accepte pas une ligne d'en-tête. P>
Le code est tout en JavaScript; Il utilise Jstree pour construire l'arborescence. Vous pouvez utiliser Firebug ou simplement voir la source sur la page pour voir comment cela est fait. Il serait probablement assez facile de le modifier pour échapper à la virgule de votre CSV afin de garder les deux derniers paramètres est un seul enfant. P>
public static void main (String arg[]) throws Exception { ArrayList<String> arRows = new ArrayList<String>(); arRows.add("A,XX,22,33"); arRows.add("A,XX,777,888"); arRows.add("A,YY,33,11"); arRows.add("B,XX,12,0"); arRows.add("A,YY,13,23"); arRows.add("B,YY,44,98"); for(String sTreeRow:createTree(arRows,",")) //or use //// or whatever applicable System.out.println(sTreeRow); } public static ArrayList<String> createTree (ArrayList<String> arRows, String sSeperator) throws Exception { ArrayList<String> arReturnNodes = new ArrayList<String>(); Collections.sort(arRows); String sLastPath = ""; int iFolderLength = 0; for(int iRow=0;iRow<arRows.size();iRow++) { String sRow = arRows.get(iRow); String[] sFolders = sRow.split(sSeperator); iFolderLength = sFolders.length; String sTab = ""; String[] sLastFolders = sLastPath.split(sSeperator); for(int i=0;i<iFolderLength;i++) { if(i>0) sTab = sTab+" "; if(!sLastPath.equals(sRow)) { if(sLastFolders!=null && sLastFolders.length>i) { if(!sLastFolders[i].equals(sFolders[i])) { arReturnNodes.add(sTab+sFolders[i]+""); sLastFolders = null; } } else { arReturnNodes.add(sTab+sFolders[i]+""); } } } sLastPath = sRow; } return arReturnNodes; }
Quelle est la grande image? En cas de ligne
a, xx, 12,34 code> Comment savez-vous que 12 et 34 appartiennent à A ou XX?