Delete duplicate string characters in a array

Did you try moving the the creation of the array, and the uniq call and printing up outside of the loop? If you define the array next to model.start_operation and uniq and print it next to commit_operation you should get one single array.

Also, you can use p variable instead of puts variable.inspect, the result is the same. puts is typically used to print pretty output to the console while p better shows the value, e.g. with quotes around strings and square brackets around arrays.

Actually the forum just leaves the tabs as tabs and it is the web browser that shows tabs at the size of 8 characters.

1 Like

If the entities are not nested, what you say is true!
Otherwise it is impossible to find all the entities in a single array.

Here is my greatly simplified code:

def list_of_definitions(ents)
  mod = Sketchup.active_model
  sel = mod.selection 
  defs_name = []  
    ents.grep(Sketchup::ComponentInstance).each do |e|
	  if e.definition.name =~ /Box/
        defs_name << e.definition.name
	  end	  
	list_of_definitions(e.definition.entities)
  end
  p defs_name
end

mod = Sketchup.active_model
sel = mod.selection
instances = sel.grep(Sketchup::ComponentInstance)
list_of_definitions(instances)

Try to nest several definitions “Box” and made a test.

The algorithm does not know what you want it to do, and it won’t do something that you don’t write in code. If you think through the algorithm step by step, you notice that the nested recursive invocation of list_of_definitions does not know the outer invocation’s defs_name array. Instead, it creates a new array. So you put them into many arrays, not into a single array. Because of that, the first (outer) defs_name array does not contain nested definition names.

To learn more about recursion, see here and this wikipedia article.

To collect all definition names into the same array, you need to share the array between all method invocations. Instead of using an instance/class variable (= side effects), a better functional way is to pass the shared array as argument in the recursive call, as I did above. The first function invocation must be given an empty array.

def list_of_definitions(ents, def_names)
  …
    list_of_definitions(e.definition.entities, def_names)
…
def_names = []
list_of_definitions(instances, def_names)
p(def_names)
2 Likes

Happy New Year everyone! :grinning:

Thank you Aerilius for your solution that works well!

def list_of_definitions(ents, defs_name)
  mod = Sketchup.active_model
  sel = mod.selection  
    ents.grep(Sketchup::ComponentInstance).each do |e|
	    if e.definition.name =~ /Box/
        defs_name << e.definition.name
	    end	  
	  list_of_definitions(e.definition.entities, defs_name)
  end
end

defs_name = []
list_of_definitions(instances, defs_name)
p defs_name.uniq 

I get 2 times a complete array of all entities “box”.

Do you know why?

how to have a single array?

Connect these two clues:

  • For every component instance whose definition name contains “Box”, you add the definition name to an array.

  • A component definition can have multiple instances.

The Ruby Console is printing the ‘return’ value of your code. In this case it is the array defs_name. Also use defs_name.uniq! to modify the array in place. Ruby array#uniq!

Try this code

def list_of_definitions(ents, defs_name)
  ents.grep(Sketchup::ComponentInstance).each do |e|
    if e.definition.name =~ /Box/
       defs_name << e.definition.name
    end	  
    list_of_definitions(e.definition.entities, defs_name)
  end
end

mod = Sketchup.active_model
sel = mod.selection
instances = sel.grep(Sketchup::ComponentInstance)
defs_name = []
list_of_definitions(instances, defs_name)
p defs_name.uniq!   # this will make more sense later when you use the array in another method
nil  #return the value Nil to the ruby console

Thanks williams!
Using “nil” to not display the array a second time is a good trick . :wink:

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.