Arrange component names
-
Hi,
I'm fairly new to ruby so I could be missing something trivial..
Say I have 200 or so components named as follows:
"001 - short description"
"002 - ..."
"003 - ..."
..and so on.Now when I need to make a new component and place it as number "052" for example - I'd need to rename all the components that follow.
I get the component definitions by:
definitions = Sketchup.active_model.definitions
component_list = []
for d in definitions
next if d.image?
next if d.group?
component_list << d
end
(thanks ThomThom: http://www.thomthom.net/thoughts/2012/02/definitions-and-instances-in-sketchup/)I then have a component_list ordered as "last modified", right?
I can get a list with the names of the components and make the necessary changes but then I have a names_list array with no way to put the names "back" to the components in the model without changing the order in which they appear.
I hope you understand what I'm trying to do
Maybe there is a better way, perhaps using hashes to store the component definition with the name?
Anyway, thanks for any advice.
/s
-
@siim11s said:
I then have a component_list ordered as "last modified", right?
The order is in no guarantied order. It doesn't change when definitions are modified.
@siim11s said:
I hope you understand what I'm trying to do
I'm afraid it's a bit unclear to me.
Are you trying to rename all definitions?
What is the expected result?@siim11s said:
Now when I need to make a new component and place it as number "052" for example - I'd need to rename all the components that follow.
Why do you need to rename all the other components to place a new component?
-
@tt_su said:
Why do you need to rename all the other components to place a new component?
I'd bet that the numeric prefix has external ordering significance (like number 053 has some relation to 054) so the existing higher numbered parts have to be pushed up when a new one is inserted into the list.
-
@tt_su said:
The order is in no guarantied order. It doesn't change when definitions are modified.
Ok, thanks.
@tt_su said:
I'm afraid it's a bit unclear to me.
Are you trying to rename all definitions?Not exactly, I'm trying to insert a new component in the middle of a name-sorted list, while keeping the numbering sequence.
@tt_su said:
What is the expected result?
List of components where the first 3 characters of the component name determine the component's position in the list.
@tt_su said:
Why do you need to rename all the other components to place a new component?
I want to place a component in position 52 in the list, so I name it "052 - ...", but there already is a component which name starts with "052" so I need all existing component names to increase their 'index' by 1.
Further:
I'm working on a wooden house frame and I need a way to get the components exported in a certain order. I have numbered the 'parts' in order of 'appearance'.
- e.g. the part you need first would be "001 - Bottom plate part - 45x95x6000". Where the "001" is the 'index' for the part and the rest is a description of it.
So, If I at some point realise that I need to insert another piece of timber, I would create a new component. But I need to place it in a certain position in the components list (which is sorted by name). If part number 052 would be a wall stud of a certain dimension and I needed to insert a new stud of another dimension next to it I want the part to be number 051 or 053 - doesn't really matter which as long as they are close.
If the component count at that point is 200, I'd need to increase the 'index' number for all components 053-200 by one.
Is this any clearer?
-
@slbaumgartner said:
I'd bet that the numeric prefix has external ordering significance (like number 053 has some relation to 054) so the existing higher numbered parts have to be pushed up when a new one is inserted into the list.
Exactly : )
-
The core issue here is to realize that there is a difference between the ordering in which items are stored in a Ruby container as they are added (which may be seemingly random - e.g. in a hash - or may be based on some optimization of the internal structure) vs the order in which they are presented by some UI or processed by code. If the order matters for the latter purposes, you should create an Array using #to_a and then sort the Array using whatever ordering rule you like.
-
@siim11s said:
@slbaumgartner said:
I'd bet that the numeric prefix has external ordering significance (like number 053 has some relation to 054) so the existing higher numbered parts have to be pushed up when a new one is inserted into the list.
Exactly : )
Here is some code for you to test. It seems to do what I understand you want.
mod = Sketchup.active_model ent = mod.active_entities sel = mod.selection cds = mod.definitions.reject{|cd|cd.group?||cd.image?} prefix=('%03d' % cds.length) new=sel.first;new_name=prefix+' - '+new.definition.name inp=UI.inputbox(["New Name;"],[new_name],"Rename #{new.definition.name}") if inp prefix,name=inp[0].split(' - ') cds.each{|cd| if cd.name.index(' - ') p,n=cd.name.split(' - ') if p.to_i >= prefix.to_i cd.name=p.next+' - '+n end end } new.definition.name=inp[0] end
-
@sdmitch said:
Here is some code for you to test. It seems to do what I understand you want.
Yes.. almost. Not quite the way I imagined it though.
It also seems to add "#1" at the end of some(?!) of the changed names.I'd prefer it wasn't dependent on the " - " in the name, rather that the first 3 characters are numbers. And I'd like to be able to sort through the whole list of numbered components in the model.. looking for consistency errors and correct them if needed. But I'll try to understand it better. Thanks!
@slbaumgartner said:
The core issue here is to realize that there is a difference between the ordering in which items are stored in a Ruby container as they are added (which may be seemingly random - e.g. in a hash - or may be based on some optimization of the internal structure) vs the order in which they are presented by some UI or processed by code. If the order matters for the latter purposes, you should create an Array using #to_a and then sort the Array using whatever ordering rule you like.
Yes, that's where I first got stuck. I have a few Ideas I can try now, thanks for the help so far.
-
@siim11s said:
Yes.. almost. Not quite the way I imagined it though.
It also seems to add "#1" at the end of some(?!) of the changed names.I'd prefer it wasn't dependent on the " - " in the name, rather that the first 3 characters are numbers. And I'd like to be able to sort through the whole list of numbered components in the model.. looking for consistency errors and correct them if needed. But I'll try to understand it better. Thanks!
The "#1" usually only occurs when you give the same name to two definitions which is why I don't name the selected component until the end.
Using the " - " seemed to be the safest option given your naming sample.
cdn = mod.definitions.map{|cd| cd.name}.sort
will give you a sorted array of the definition names.
-
Try the following (based on SDMitch's code)
mod = Sketchup.active_model ent = mod.active_entities sel = mod.selection cds = mod.definitions.reject{|cd|cd.group?||cd.image?} prefix=('%03d' % cds.length) new=sel.first;new_name=prefix+' - '+new.definition.name inp=UI.inputbox(["New Name;"],[new_name],"Rename #{new.definition.name}") reInc = /^(\d{3})(.+)/ if (reInc.match(inp[0])) new.definition.name = inp[0] iPre = $1.to_i iCD = 0 cds.each { |cd| if (reInc.match(cd)) iCD = $1.to_i + 1 cd.name = "%03d#{$2}" %iCD if iCD > iPre end } end
As long as the cd name begins with three numbers...
Note - no testing for prefixes greater than 999, and no testing for duplicate names after the increment.
Greg
-
@msp_greg said:
Try the following (based on SDMitch's code)
> mod = Sketchup.active_model > ent = mod.active_entities > sel = mod.selection > cds = mod.definitions.reject{|cd|cd.group?||cd.image?} > prefix=('%03d' % cds.length) > new=sel.first;new_name=prefix+' - '+new.definition.name > inp=UI.inputbox(["New Name;"],[new_name],"Rename #{new.definition.name}") > reInc = /^(\d{3})(.+)/ > if (reInc.match(inp[0])) > new.definition.name = inp[0] > iPre = $1.to_i > iCD = 0 > cds.each { |cd| > if (reInc.match(cd)) > iCD = $1.to_i + 1 > cd.name = "%03d#{$2}" %iCD if iCD > iPre > end > } > end >
As long as the cd name begins with three numbers...
Note - no testing for prefixes greater than 999, and no testing for duplicate names after the increment.
Greg
Greg,
Tried your code and found two problems.
-
if(reInc.match(cd)) needs to be if(reInc.match(cd.name))
-
the prefix of the new name entered gets incremented as well. the new.definition.name = inp[0] statement needs to be the last thing done in the if (reInc.match(inp[0])) section.
-
-
siim11s,
The previous code I posted didn't allow for name collisions. Below code should allow for it. Also added a few comments...
# reInc checks for match of three digits at beginning of string, # loads digits into $1, rest of name into $2 reInc = /^(\d{3})(.+)/ if (reInc.match(inp[0])) # sort reverse so name colisions won't occur cds.sort! { |a,b| b.name <=> a.name } # initialize loop variables iPre = $1.to_i iCD = 0 cds.each { |cd| if (reInc.match(cd.name)) iCD = $1.to_i + 1 # since we're reverse sorted, break when we reach low numbers break if iCD <= iPre cd.name = "%03d#{$2}" %iCD end } new.definition.name = inp[0] end # for testing, use below to resort & output new names cds.sort! { |a,b| a.name <=> b.name } cds.each { |cd| puts cd.name }
Greg
-
SDMitch (Mitch?),
@sdmitch said:
Tried your code and found two problems.
- if(reInc.match(cd)) needs to be if(reInc.match(cd.name))
Thanks for the catches. I edited & corrected the second post. I tested mine with a string array, not an array of cd's. Hence, no name prop.
@sdmitch said:
- the prefix of the new name entered gets incremented as well.
That's why you had the new cd name assign at the end of the loop. That's why I shouldn't change code after I've tested it...
Thanks,
Greg
Advertisement