plantuml: Right to left arrows, grouped components - plantuml

I have the following diagram:
#startuml
left to right direction
rectangle Foo1
rectangle Foo2
rectangle Foo3
node Bar1
node Bar2
node Bar3
storage Baz1
storage Baz2
storage Baz3
Foo1 --> Bar2
Foo2 --> Bar1
Bar1 --> Baz3
Bar2 --> Baz1
#enduml
Where some components are orphaned and dont have arrows. see here It renders fine but the orphaned components are all listed at the first tier.
I want to modify it so that I would have my components arranged like this:
Foo1 -> Bar2 -> Baz1
Foo2 -> Bar1 -> Baz3
Foo3 Bar3 Baz2
update:
#albert points out that we can use invisible arrows to get the effect we want. And it works.
What if however we had something like:
#startuml
left to right direction
rectangle Foo1
rectangle Foo3
node Bar1
node Bar2
node Bar3
storage Baz1
storage Baz2
storage Baz3
Foo1 --> Bar2
Bar1 --> Baz3
Bar2 --> Baz1
#enduml
we'd get something like this: + I suppose we could add the following hidden arrows:
Foo1 -[#hidden]-> Bar1
Foo1 -[#hidden]-> Bar3
Bar2 -[#hidden]-> Baz2
and that would give us the desired effect or in text-form:
Foo3 Bar1 Baz3
Foo1 Bar2 Baz1
Bar3 Baz2
Would be great if we could add invisible components FooH, BarH. ie:
FooH -[#hidden]-> Bar1
FooH -[#hidden]-> Bar3
BarH -[#hidden]-> Baz2
ie we'd use hidden arrows for invisible components which would separate them from legitimate arrows. I can't however find an easy way of marking a component as invisible.

I think that one of the key point here will be the [hidden] for the arrow.
You would start using using something like:
#startuml
left to right direction
rectangle Foo1
rectangle Foo2
rectangle Foo3
node Bar1
node Bar2
node Bar3
storage Baz1
storage Baz2
storage Baz3
Foo1 --> Bar2
Foo2 --> Bar1
Bar1 --> Baz3
Bar2 --> Baz1
Foo3 -[hidden]-> Bar3
Bar3 -[hidden]-> Baz2
#enduml
edit
When you want to hide a component like Foo1 you can use e.g.
hide Foo1

Related

How to amend object in an array with duplicate attributes? (XY coordinates)

I have an array of objects (nodes) with XY coordinates. Wherever I find a node overlaying another node (with the exact same XY coords) I would like to edit the Y attribute "up" by 3.
id, x, y are all attributes of the objects I am looking at. And collectively held in an Array of nodes.
I am looking to go through the array and whenever a duplicate XY is present, edit the first non-unique instance by adding 3 to the Y attribute. If another duplicate is found, I would like this object's Y attribute to be altered by 6 and so on.
E.g.
NODE X Y
node1 267555 666777
node2 267555 666777
node3 245698 656400
node4 267555 666777
I would like node 2 and node 4 to become:
NODE X Y
node1 267555 666777
node2 267555 666780
node3 245698 656400
node4 267555 666783
Essentially adding 3 to 'Y' for every instance of a duplicate XY, and doing so for every instance where there are overlying nodes in the array (the real array is much larger).
I have managed to identify duplicates using, but unsure of how to proceed:
duplicates = nodes.group_by{|i| [i.x, i.y] }.select{|k,v| v.length > 1}.values
However I don't want a new array, I wish to amend the original "nodes" array attributes.
Thanks
Let's start by creating a class of nodes.
class Nodes
attr_accessor :name, :x, :y
def initialize(name, x, y)
#name = name
#x = x
#y = y
end
end
Next, create the instances shown in the problem.
nodes = [
Nodes.new("node1", 267555, 666777),
Nodes.new("node2", 267555, 666777),
Nodes.new("node3", 245698, 656400),
Nodes.new("node4", 267555, 666777)
]
#=> [#<Nodes:0x00005c7949ee8e40 #name="node1", #x=267555, #y=666777>,
# #<Nodes:0x00005c7949f57c50 #name="node2", #x=267555, #y=666777>,
# #<Nodes:0x00005c7949f57958 #name="node3", #x=245698, #y=656400>,
# #<Nodes:0x00005c7949f577a0 #name="node4", #x=267555, #y=666777>]
Now modify the y values as desired. For this we make use of the form of the method Hash::new that takes an argument called the default value. If a hash h has been created this way, h[k] will return the default value if it does not have a key k. This is sometimes called a counting hash.
nodes.each_with_object(Hash.new(0)) do |inst,h|
y = inst.y
inst.y += 3 * h[y] if h.key?(y)
h[y] += 1
end
#=> {666777=>3, 656400=>1}
Let's see what nodes looks like now.
nodes
#=> [#<Nodes:0x00005c7949ee8e40 #name="node1", #x=267555, #y=666777>,
# #<Nodes:0x00005c7949f57c50 #name="node2", #x=267555, #y=666780>,
# #<Nodes:0x00005c7949f57958 #name="node3", #x=245698, #y=656400>,
# #<Nodes:0x00005c7949f577a0 #name="node4", #x=267555, #y=666783>]
nodes.map { |inst| [inst.name, inst.x, inst.y] }
#=> [["node1", 267555, 666777],
# ["node2", 267555, 666780],
# ["node3", 245698, 656400],
# ["node4", 267555, 666783]]

How to map with different parameters - ruby

I'm creating some tests and I would like to create an array of objects passing different parameters to the constructor, is there a smart way of doing that?
For example, suppose I have this code:
foos = 3.times.map{ Foo.new("a") }
This code would give me an array with 3 foo's, but all of them initialized with the "a" parameter.
I would rather have an array where the first one is initialized with "a", the second with "b" and the third with "c", like it would if did this:
foos = [Foo.new("a"),Foo.new("b"),Foo.new("c")]
Is there a smarter way of doing this?
Try this one
%w(a b c).map { |s| Foo.new(s) }
In case you don't know
%w(a b c)
is a shorter way to say
["a", "b", "c"]
Going a bit deeper on your question, I'm going to suggest you two libraries: Factory Girl and Faker. None is Rails nor Rspec specific.
With Factory Girl you can define factories to create test data and with Faker you can associate randomized data to your factories.
I'm suggesting these two libraries because creating test data for simple use cases is easy, but it starts to get very complicated when you have more complex relationships between objects.
Here's an example to get you started:
class Foo < Struct.new(:bar)
end
FactoryGirl.define do
factory :foo do
bar Faker::Number.digit
end
end
FactoryGirl.build_list(:foo, 3)
=> [#<struct Foo bar=3>, #<struct Foo bar=2>, #<struct Foo bar=7>]
FactoryGirl.build(:foo)
=> #<struct Foo bar=5>
FactoryGirl.build(:foo, bar: 2)
=> #<struct Foo bar=2>
Here are more examples on how powerful Factory Girl is. Just remember that you need to use the build* methods instead of create* methods, because create* methods also call on save to persist the data when using it with a persistence layer.
Just to offer an alternative:
arr = ['a', 'b', 'c']
Array.new(arr.size) { |i| Foo.new arr[i] }
#=>
#[#<Foo:0x000000025db798 #arg="a">,
# #<Foo:0x000000025db748 #arg="b">,
# #<Foo:0x000000025db6d0 #arg="c">]

How do I define a slice of slices containing an int and a slice of strings in Go?

It would look something like this:
[[1,["a", "b", "c"]], [2,["z", "x", "y"]]]
Intuitively I would do something like [][]int[]string, but that's not valid: syntax error: unexpected [, expecting semicolon or newline or }, so how would I do it?
Slice of T: var x []T
Slice of slice of T: var x [][]T
Slice of T1 and T2: You need to put T1 and T2 into a struct.
So for: slice of (slices containing { int and a slice of strings } ).
It would usually be something like:
type foo struct {
i int
s []string
}
var x [][]foo
But your example looks more like just a []foo:
bar := []foo{
{1, []string{"a", "b", "c"}},
{2, []string{"z", "x", "y"}},
}
fmt.Println("bar:", bar)
// bar: [{1 [a b c]} {2 [z x y]}]
Run on Playground (also includes more examples)

How to Retrieve array key values in Tcl

Given Data
array set color {a red b green c blue}
set keylist [array names $color]
pointlist {{1 2 3 4} {5 6 7 8} {9 10 11 12} {13 14 15 16}}
I get a new list after running a procedure.
newlist {b b b b} # Note: length of newlist is same as length of pointlist
Question is : when i run a loop these values of b should be substituted, for example in this green.
for {set i 0} { $i < [llength $pointlist]} {incr i } {
lassign [lindex $pointlist $i] x1 y1 x2 y2
APICommand -points "$x1,$y1,$x2,$y2" -color $color($keylist)
}
Now this $color($keylist) is not getting me correct result and errors out saying :
can't read "color(red blue green)": no such element in array
Instead I want the first set of 4 points to get the green color which is the value of b. Similarly next set of 4 points from pointlist should also get green as its value is also b.
#So, after substitution it should look like APIcommand -points 1,2,3,4 -color green ..... so on and so forth
Note this will not always be b , it just happens to be in this case.
Need solution asap. Thanks in advance.
Sounds like you need $color([lindex $newlist $i])
When iterating across a list, the foreach command is useful. It can also be used to iterate over multiple corresponding lists. Assuming newlist holds the colors that correspond to the points, I might try something like (usual warnings about untested code):
foreach point $pointlist new $newlist {
APICommand -points [join $point ,] -color $color($new)
}

ZSH print array objects in color to terminal window

Still learning shell scripting and ZSH. But was wondering if someone knew how to create an array of simple objects think, json type objects/hashes, and then print the properties of each object in column format in different colors.
I want to create a specific function in my zsh plugin that prints to my terminal in a very precise way.
Open questions:
1.) How to print specific strings in different colors
2.) How to define arrays of basic objects with multiple key/value pairs
The following pseudo code will hopefully clarify what I am trying to do.
function display-collection() {
collection=(
{param1: foo1, param2: bar1, param3: baz1 }
{param1: foo2, param2: bar2, param3: baz2 }
{param1: foo3, param2: bar3, param3: baz3 }
{param1: foo4, param2: bar4, param3: baz4 }
{param1: foo5, param2: bar5, param3: baz5 }
{param1: foo6, param2: bar6, param3: baz6 }
)
print -l $collection
}
Make the above function spit out the contents to the terminal in color
foo1 (RED TEXT) bar1 (DEFAULT COLOR) baz1 (YELLOW COLOR)
foo2 (RED TEXT) bar2 (DEFAULT COLOR) baz2 (YELLOW COLOR)
foo3 (RED TEXT) bar3 (DEFAULT COLOR) baz3 (YELLOW COLOR)
foo4 (RED TEXT) bar4 (DEFAULT COLOR) baz4 (YELLOW COLOR)
foo5 (RED TEXT) bar5 (DEFAULT COLOR) baz5 (YELLOW COLOR)
foo6 (RED TEXT) bar6 (DEFAULT COLOR) baz6 (YELLOW COLOR)
In other words column text like this with each column color coorindated
the foo values would be red, the bar values would be default and the baz values would be yellow
foo1 bar1 baz1
foo2 bar2 baz2
foo3 bar3 baz3
foo4 bar4 baz4
foo5 bar5 baz5
foo6 bar6 baz6
Bonus points if I can format the alignment to be nice ordered columns, with arbitrary delimiters/separators.
foo1 : bar1 = baz1
string1 : some string = another string
string2 : some longer string = another longer string
helloworld : This is a function = it prints helloworld
Question #1: see this StackOverflow question. A Google search for "colored function output linux" gives a bunch of links which I'm assuming you've read (because you did search prior to asking this question, right..?). What's your specific issue with colored output?
Question #2: Is a simple array not enough? Your example:
param1: foo1, param2: bar1, param3: baz1
param1: foo2, param2: bar2, param3: baz2
This appears to always have param1 in the 1st, 4th, 7th (ie, 1+3Nth position). param2 in 2+3Nth, and param3 in 3+3Nth. Inserting param1: into your data-structure seems awfully redundant.
A 1-dimensional array would fit this; it's just a matter of printing.
Chapter 2 of 'A Users Guide to the Z-Shell', section 2.4.1, "Arrays", is about Arrays in zsh.
I would create a function specifically to print an array.
function print-array-collection() {
autoload -Uz colors && colors # See Note 3.
local array_name=$1
local array_length=${#${(P)${array_name}}}
for (( i = 1; i < $array_length; i+=3 )) do
print -P %{${fg[red]}%}${(P)${array_name}[i]}%{$reset_color %}${(P)${array_name}[i+1]} %{${fg[yellow]}%}${(P)${array_name}[i+2]}%{$reset_color%}
done
}
Notes:
Here is how the array is passed into the function.
This answer should explain the loop.
The zsh color module provides an easier way to type the colors than the ANSII escape codes.
Use print -P because it'll expand the prompt sequences. Read the section on print in man zshbuiltins for more information.
Here's a sample:
Bonus Questions: Setting the delimiters should be pretty easy (insert another variable in the print -P statement.
Tab-delimitation is probably not too difficult. Printing the longest item in the array can be done using the majestic-looking:
print ${array[(r)${(l.${#${(O#)array//?/X}[1]}..?.)}]}
which is taken from Chapter 5, paragraph 1, of the 'A Users guide to the Z-Shell'. The length of a variable can be determined using the ${#${variable}} syntax (as done in the function above). I'll leave the rest to you ;)

Resources