Suppose that you have a list of formulas like the following one:
KPI1 = somevalue1 + somevalue2
KPI2 = somevalue1 + somevalue3
KPI3 = KPI1 + somevalue4
KPI4 = KPI2 + KPI3
etc.
Which is the optimal algorithm that can be used to obtain a relationship tree for each of the elements referenced in the formulas?
i.e., using the example above:
+------------------------------------------------------------+
| somevalue3 somevalue1 somevalue2 somevalue4 |
| | | | | | |
| --------------- -------------- | |
| | | | |
| KPI2 KPI1 | |
| | | | |
| | --------------------- |
| | | |
| | KPI3 |
| | | |
| --------------------------- |
| | |
| KPI4 |
+------------------------------------------------------------+
You can use a hashmap where a key corresponds to a defined name (e.g. "KPI3"), and the corresponding value is a list of names/values on which that name depends (e.g. ["KPI1", somevalue4]).
Here is an implementation in JavaScript, where we can use the native Map constructor. Once the map is populated with all the dependencies, a recursive function can for example print the tree:
function printTree(map, name, indent="") {
console.log(indent + name);
let children = map.get(name);
if (children !== undefined) {
for (let childName of children) {
printTree(map, childName, indent+" ");
}
}
}
let map = new Map();
map.set("KPI1", ["value1", "value2"]);
map.set("KPI2", ["value1", "value3"]);
map.set("KPI3", ["KPI1", "value4"]);
map.set("KPI4", ["KPI2", "KPI3"]);
printTree(map, "KPI4");
In Python you would use a dictionary:
def print_tree(d, name, indent=""):
print(indent + name)
children = d.get(name, None)
if children is not None:
for childName in children:
print_tree(d, childName, indent+" ")
d = dict()
d["KPI1"] = ["value1", "value2"]
d["KPI2"] = ["value1", "value3"]
d["KPI3"] = ["KPI1", "value4"]
d["KPI4"] = ["KPI2", "KPI3"]
print_tree(d, "KPI4")
Related
I have:
hash = {"1"=>["A", "B", "C", ... "Z"], "2"=>["B", "C"], "3"=>["A", "C"]
My goal is to use hash as a source for creating a CSV with columns whose names are a letter of the alphabet and with rows hash(key) = 1,2,3 etc.
I created an array of all hash.values.unshift("")values that serve as row 1 (columns labels).
desired output:
| A | B | C | ... | Z |
1| A | B | C | ... | Z |
2| | B | C | ....... |
3| A | | C | ....... |
Creating CSV:
CSV.open("groups.csv", 'w') do |csv|
csv << row1
hash.each do |v|
csv << v.flatten
end
end
This makes the CSV look almost what I want but There is no spacing to get columns to align.
Any advice on how to make a method for modifying my hash that compares my all [A-Z] against each subsequent hash key (rows) to insert empty strings to provide spacing?
Can Class CSV do it better?
Something like this?
require 'csv'
ALPHA = ('A'..'Z').to_a.freeze
hash={"1"=>ALPHA, "2"=>["B", "C"], "3"=>["A", "C"]}
csv = CSV.generate("", col_sep: "|") do |csv|
csv << [" "] + ALPHA # header
hash.each do |k, v|
alphabet = ALPHA.map { |el| [el, 0] }.to_h
v.each { |el| alphabet[el] += 1 }
csv << [k, *alphabet.map { |k, val| val == 1 ? k : " " }]
end
end
csv.split("\n").each { |row| puts row }
output:
|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z
1|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z
2| |B|C| | | | | | | | | | | | | | | | | | | | | | |
3|A| |C| | | | | | | | | | | | | | | | | | | | | | |
If your values are truly single characters and don't need the CSV escaping, then I recommend bypassing CSV altogether and building the string in plain Ruby.
Assuming you want to align your lines correctly regardless of the number of digits in the row number (e.g. 1, 10, and 100), you can use printf style formatting to guarantee horizontal aligment (assuming your row number width never exceeds the value of ROWNUM_WIDTH).
By the way, I changed the hash's keys to integers, hope that's ok.
#!/usr/bin/env ruby
FIELDS = ('A'..'Z').to_a
DATA = { 1 => FIELDS, 2 => %w(B C), 3 => %w(A C) }
ROWNUM_WIDTH = 3
output = ' ' * ROWNUM_WIDTH + " | #{FIELDS.join(' | ')} |\n"
DATA.each do |rownum, values|
line = "%*d | " % [ROWNUM_WIDTH, rownum]
FIELDS.each do |field|
char = values.include?(field) ? field : ' '
line << "#{char} | "
end
output << line << "\n"
end
puts output
=begin
Outputs:
| A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
1 | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
2 | | B | C | | | | | | | | | | | | | | | | | | | | | | | |
3 | A | | C | | | | | | | | | | | | | | | | | | | | | | | |
=end
all = [*?A..?Z]
hash = {"1"=>[*?A..?Z], "2"=>["B", "C"], "3"=>["A", "C"]}
hash.map do |k, v|
[k, *all.map { |k| v.include?(k) ? k : ' ' }]
end.unshift([' ', *all]).
map { |row| row.join('|') }
#⇒ [
# [0] " |A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z",
# [1] "1|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z",
# [2] "2| |B|C| | | | | | | | | | | | | | | | | | | | | | | ",
# [3] "3|A| |C| | | | | | | | | | | | | | | | | | | | | | | "
# ]
The problem i am trying to solve is, I have routing table
|src|dest|port|
| a | b | p1 |
| a | b | p2 |
| a | b | p3 |
| a | c | p1 |
| a | d | p2 |
| a | e | p3 |
This can be optimized to
|src|dest|port|
| a | b |p1,p2,p3|
| a | c | p1 |
| a | d | p2 |
| a | e | p3 |
Which can further be optimized to
|src|dest|port|
| a |b,c | p1 |
| a |b,d | p2 |
| a |b,e | p3 |
I thought of using 3 dimensional representation to solve this problem but again the retrieval will be complicated.
I need to use the best data structure to solve this use case.
The data structure is a set of sets of dest values, where the first set is keyed by src values and the second set is keyed by port values. This groups dest values by src and port:
src => port => [dest]
In python, this can be done with dictionaries:
table = (
('a','b','p1'),
('a','b','p2'),
('a','b','p3'),
('a','c','p1'),
('a','d','p2'),
('a','e','p3'),
)
optimized = {}
for route in table:
src, dest, port = route
o = optimized.get(src, {})
p = o.get(port, [])
p.append(dest)
o[port] = p
optimized[src] = o
for src,route in optimized.iteritems():
for port,dest in route.iteritems():
print src, dest, port
The result (in unsorted order) is:
a ['b', 'd'] p2
a ['b', 'e'] p3
a ['b', 'c'] p1
The lookup can be done using:
dest = optimized[src][port]
Here i have two tables
Table One
+---------------+----------+------------+
| Raw Material | Size | Qty |
+---------------+----------+------------+
| A | 1 | 5 |
| A | 2 | 2 |
| A | 1 | 2 |
| B | 0 | 5 |
| B | 0 | 1 |
+---------------+----------+------------+
Table Two
+---------------+----------+------------+
| Raw Material | Size | Qty |
+---------------+----------+------------+
| A | 1 | 2 |
| A | 2 | 1 |
| A | 1 | 1 |
+---------------+----------+------------+
I want out put like
+---------------+----------+------------+
| Raw Material | Size | Qty |
+---------------+----------+------------+
| A | 1 | 4 |
| A | 2 | 1 |
| B | 0 | 6 |
+---------------+----------+------------+
Want to get substract first two tables sum of qty by grouping Rawmaterial and Size
Something like this should do the job
var result = tableA.Select(e => new { Item = e, Factor = 1 })
.Concat(tableB.Select(e => new { Item = e, Factor = -1 }))
.GroupBy(e => new { e.Item.RawMaterial, e.Item.Size }, (key, elements) => new
{
RawMaterial = key.RawMaterial,
Size = key.Size,
Qty = elements.Sum(e => e.Item.Qty * e.Factor)
}).ToList();
First we create a union of the two tables using Concat, including the information which one is additive (in Factor field), and then just do the normal grouping.
If you want the result to be List<YourTableElementType>, just replace the final anonymous type projection (new { ... }) with new YourTableElementType { ... }.
Here's what I'm trying to do. I'm iterating through an array of strings, each of which may contain [] multiple times. I want to use String#match as many times as necessary to process every occurrence. So I have an Array#each block, and nested within that is an infinite loop that should break only when I run out of matches for a given string.
def follow(c, dir)
case c
when "\\"
dir.rotate!
when "/"
dir.rotate!.map! {|x| -x}
end
return dir
end
def parse(ar)
ar.each_with_index { |s, i|
idx = 0
while true do
t = s.match(/\[[ ]*([a-zA-Z]+)[ ]*\]/) { |m|
idx = m.end 0
r = m[1]
s[m.begin(0)...idx] = " "*m[0].size
a = [i, idx]
dir = [0, 1]
c = ar[a[0]][a[1]]
while !c.nil? do
dir = follow c, dir
ar[a[0]][a[1]] = " "
a[0] += dir[0]; a[1] += dir[1]
c = ar[a[0]][a[1]]
if c == ">" then
ar[a[0]][a[1]+1] = r; c=nil
elsif c == "<" then
ar[a[0]][a[1]-r.size] = r; c=nil
end
end
ar[a[0]][a[1]] = " "
puts ar
}
if t == nil then break; end
end
}
parse File.new("test", "r").to_a
Contents of test:
+--------+----------+-------------+
| Colors | Foods | Countries |
+--------+----------+-------------+
| red | pizza | Switzerland |
/--> /----> | |
| |[kale]/ | hot dogs | Brazil |
| | <----------------------\ |
| | orange |[yellow]\ | [green]/ |
| +--------+--------|-+-------------+
\-------------------/
Goal:
+--------+----------+-------------+
| Colors | Foods | Countries |
+--------+----------+-------------+
| red | pizza | Switzerland |
yellow kale | |
| | hot dogs | Brazil |
| green |
| orange | | |
+--------+-------- -+-------------+
Actual output of program:
+--------+----------+-------------+
| Colors | Foods | Countries |
+--------+----------+-------------+
| red | pizza | Switzerland |
yellow kale | |
| | hot dogs | Brazil |
| <----------------------\ |
| orange | | [green]/ |
+--------+-------- -+-------------+
(Since the array is modified in place, I figure there is no need to update the match index.) The inner loop should run again for each pair of [] I find, but instead I only get one turn per array entry. (It seems that the t=match... bit isn't the problem, but I could be wrong.) How can I fix this?
I'm trying to produce a web page report of Orders Per Customer with line item details for each order.
So it looks like this:
Customer 1 | Order 1 | Item 1 |
| | == New Row == |
| | Item 2 |
| | == New Row == |
| | Item 3 |
| | == New Row == |
| ====== New Row ========= |
| Order 2 | Item 1 |
| | == New Row == |
| | Item 2 |
| | == New Row == |
| | Item 3 |
| | == New Row == |
| ====== New Row ========= |
| Order 3 | Item 1 |
| | Item 2 |
== New Row ==============================
Customer 2 | Order 1 | Item 1 |
| | == New Row == |
| | Item 2 |
| | == New Row == |
| | Item 3 |
| | == New Row == |
| | Item 4 |
| | == New Row == |
| | Item 5 |
| | == New Row == |
| ====== New Row ========= |
| Order 2 | Item 1 |
| | == New Row == |
| | Item 2 |
| | == New Row == |
| | Item 3 |
== New Row ==============================
Is it better to get an array list of data as follows:
1 | 1 | 1 |
1 | 1 | 2 |
1 | 1 | 3 |
1 | 2 | 1 |
1 | 2 | 2 |
1 | 2 | 3 |
1 | 3 | 1 |
1 | 3 | 2 |
2 | 1 | 1 |
2 | 1 | 2 |
2 | 1 | 3 |
2 | 1 | 4 |
2 | 1 | 5 |
2 | 2 | 1 |
2 | 2 | 2 |
2 | 2 | 3 |
and pass 1 JavaBean and use JSTL to determine the nesting as follows:
this is incomplete for brevity
<table><tr><th>Customer No</th><th>Orders</th></tr>
<c:forEach var="custOrderLineItem" items="${customerOrderLineItemList}">
<c:set var="currentOrder" value="custOrderLineItem.orderId">
<c:set var="currentCustomer" value="custOrderLineItem.customerId">
<c:if test="${currentOrder != custOrderLineItem.orderId}">
==New Row==
</c:if>
or is it better to use nested JavaBeans
Customer.setOrders<List>
Orders.setOrderDetails<List>
OrderDetails.setLineItem<List>
and then use JSTL as such
<c:forEach var="customer" items="${customerList}">
<c:forEach var="order" items="${customer.orderList}">
<c:forEach var="lineItem" items="${order.detailList}">
After spending the time writing this, I feel like the second method looks cleaner and easier. But the first method seems to have an easier SQL query. I'm not using JPA, just basic JDBC sql calls. So how does one populate nested JavaBeans, without JPA? Do you do something like this?
List<Customer> custList = getCustomerList();
ListIterator custListIter = custList.listIterator();
while (custListIter.hasNext()) {
customer = (Customer) custListIter.next();
List<Order> orderList = getOrderList(customer.getId());
ListIterator orderListIter = orderList.listIterator();
while (orderListIter.hasNext()) {
order = (Order) orderListIter.next();
List orderDetailsList<OrderDetail> = getOrderDetailList(order.getId);
order.setOrderDetails(orderDetailsList);
orderListIter.set(order);
}
customer.setOrderList(orderList);
custListIter.set(customer);
}
You could simply make the SQL query which returns everything, and build the graph of objects from the result set. Using maps to keep an association between IDs and the corresponding objects:
Map<Long, Customer> customersById = new HashMap<Long, Customer>();
Map<Long, Order> ordersById = new HashMap<Long, Order>();
Map<Long, Item> itemsById = new HashMap<Long, Item>();
while (rs.next()) {
Long customerId = rs.getLong(1);
Customer customer = customersById.get(customerId);
if (customer == null) {
customer = new Customer(customerId);
// populate other fields of customer
customersById.put(customerId, customer);
}
Long orderId = rs.getLong(5);
Order order = ordersById.get(orderId);
if (order == null) {
order = new Order(orderId);
customer.addOrder(order);
// populate other fields of order
ordersById.put(orderId, order);
}
// same for items
}
At the end of the loop, you have all the customers, each with their orders, each with their items.