Question

J'ai une structure arborescente dans un fichier .csv (nœuds sont de type texte), et après avoir lu le csv je veux stocker les données dans un objet rubis. Je suis passé par quelques plugins d'arbres et je pense que nested_set servirait le but pour moi. Cependant, je suis problème auquel est confronté avec la fixation d'un format de fichier csv, afin que je puisse le lire et convertir en objet arbre. Est-il possible de convertir directement un fichier de format CSV ou deux matrice bidimensionnelle, en une structure de données arborescente ??

Était-ce utile?

La solution

Après avoir éclairci que vous n'avez pas besoin de stocker cet arbre dans la base de données, je vous suggère de jeter NestedSets (ils sont pour stocker des ensembles d'objets imbriqués sur SGBDR, que vous n'avez pas besoin). Qu'est-ce que vous avez besoin i simple arbre

class Node
  attr_accessor :parent, :children, :text

  def initialize(text)
    @text = text
    @children = []
  end
end

Comme je l'ai droit de choisir le format de fichier CSV, alors je suggère STH comme ceci:

id,parent,text
1,,"1"
2,1,"1.1"
3,1,"1.2"
3,2,"1.1.1"

racine de l'arbre est première rangée, sans parents, et il y a toujours l'ordre que parent est déclaré devant ses enfants. De cette façon, vous pouvez construire arbre

def build_tree(rows)
  nodes = {}
  rows.each do |row|
    node = Node.new(row[:text])
    nodes[row[:id]] = node

    node.parent = nodes[row[:parent]]
    nodes[row[:parent]].children << node if row[:parent]
  end

  nodes.values.find {|node| node.parent.nil? }
end

root = build_tree(rows)
root.text #=> "1"
root.children.map(&:text) #=> ["1.1", "1.2"]
root.children[0].children.map(&:text) #=> ["1.1.1"]

Si vous avez besoin pour obtenir tous les textes de sous-noeuds, alors vous devez utiliser plus astuces

def get_nodes(tree_node)
  [ tree_node, tree_node.children.map{|node| get_nodes(node)} ].flatten
end

get_nodes(root).map(&:text) #=> ["1", "1.1", "1.1.1", "1.2"]

Autres conseils

Il semble que vous n'avez pas besoin d'utiliser ORM du tout. Pourquoi ne pas faire votre logique d'arbre vous, avec un langage dynamique comme Ruby, il est assez facile:

require 'set'

# expects an array of [parent, child] pairs, returns the root element of a tree
def make_tree a
  tree = {}

  a.each do |p, c|
    tree[p] ||= {:value => p}
    tree[p][:children] ||= Set.new
    tree[c] ||= {:value => c}
    tree[c][:parent] = tree[p]
    tree[p][:children] << tree[c]
  end

  tree.values.find{|e| e[:parent].nil?}
end

root = make_tree [[1,2],[3,4],[1,3],[4,5]]

puts root.inspect
puts root[:value]

Ou, si vous voulez plus OO, vous pouvez faire classe TreeNode au lieu de Hash ci-dessus.

Oh, et si vous avez besoin d'accéder à des nœuds d'arbres particuliers directement par leur clé (dans ce cas, la valeur entière lui-même), changer la méthode pour revenir hachage tree au lieu de simplement l'élément racine.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top