I have an array of pairs like this:
[["a", "b"], ["b", "d"], ["a", "c"], ["e", "d"], ["a", "d"], ..., ["s", "f"]]
What is an efficient way to check if the given array can express a partial ordering? That is, there is no "loop" in the given array like ["a", "b"], ["b", "c"], ["c", "a"].
If it is confirmed that the array expresses a partial order, I want to normalize this by removing all of the pairs that can be derived by reflexivity or transitivity. For example, in the above, since there is ["a", "b"] and ["b", "d"], the pair ["a", "d"] is redundant, and should be removed.
The order between 1 and 2 does not matter. If 2 should be done before or within the process of 1, then, that is fine.
Preferably I want it in Ruby 1.9.3, but just pseudo-code will suffice.
For number 1:
You can module your problem as a graph, and each pair will be an edge, next you can run a topological sort - if the algorithm fails, the graph is not a DAG - and there is a "loop" - otherwise - you get a possible partial order, as the output of the topological sort.
For number2:
I am not sure regarding this part at all, so this answer is only partial actually, sorry about it - but just a priliminary thaught:
You can use a DFS, and remove edges from "already discovered" vertices to "just discovered vertices" [on the same path]. Though I don't think it is optimal, but prehaps doing it iteratively [until no changes were made] will improve it.
Deeper thaught for number2:
I am not sure what you mean here, but a forest created by DFS fulfill your request, however I am afraid you might lose too much data using it, for instance: ["a","b"],["a","c"],["b",d"],["c","d"] will trim one of ["b","d"] OR ["c","d"], which might be too much, but it will also trim all the "redundant" edges, as described in the example.
The second problem is known as transitive reduction.
For the first part of the question, I came up with my own answer here with the help of an answer at a mathematics site.
For the second part of the question, after following the suggestions given in the other answers, I implemented in Ruby (i) Floyd-Warshall algorithm to calculate the transitive closure, (ii) composition, and (iii) transitive reduction using the formula R^- = R - R \cdot R^+.
module Digraph; module_function
def vertices graph; graph.flatten(1).uniq end
## Floyd-Warshall algorithm
def transitive_closure graph
vs = vertices(graph)
path = graph.inject({}){|path, e| path[e] = true; path}
vs.each{|k| vs.each{|i| vs.each{|j| path[[i, j]] ||= true if path[[i, k]] && path[[k, j]]}}}
path.keys
end
def compose graph1, graph2
vs = (vertices(graph1) + vertices(graph2)).uniq
path1 = graph1.inject({}){|path, e| path[e] = true; path}
path2 = graph2.inject({}){|path, e| path[e] = true; path}
path = {}
vs.each{|k| vs.each{|i| vs.each{|j| path[[i, j]] ||= true if path1[[i, k]] && path2[[k, j]]}}}
path.keys
end
def transitive_reduction graph
graph - compose(graph, transitive_closure(graph))
end
end
Usage examples:
Digraph.transitive_closure([[1, 2], [2, 3], [3, 4]])
#=> [[1, 2], [2, 3], [3, 4], [1, 3], [1, 4], [2, 4]]
Digraph.compose([[1, 2], [2, 3]], [[2, 4], [3, 5]])
#=> [[1, 4], [2, 5]]
Digraph.transitive_reduction([[1, 2], [2, 3], [3, 4], [1, 3], [1, 4], [2, 4]])
#=> [[1, 2], [2, 3], [3, 4]]
Related
Would like to exploit the following behaviour in Ruby
ary = Array.new(5) { |i|
[i, j=2*i, k=j+1]
}
p ary #> [[0, 0, 1], [1, 2, 3], [2, 4, 5], [3, 6, 7], [4, 8, 9]]
It works for my purposes, but I couldn't find in the language definition whether this is legal Ruby. Is it? Or is it likely to break in the future?
[Edit] A smaller working example raising the same issue is
i = 1
ary = [i, j=2*i, k=j+1]
p ary #> [1, 2, 3]
But of course this example only has theoretical relevance contrary to the first, which does have practical relevance.
I'm trying to combine elements from one array with every element from another array, I tried looking for some solutions but I couldn't figure it out.
Take these two arrays for example:
num = [1,2,3]
let = ["a","b","c"]
I want to combine them in order to obtain:
combined = [[1, "a"], [1, "b"], [1, "c"], [2, "a"], [2, "b"], [2, "c"],
[3, "a"], [3, "b"], [3, "c"]]
You can use #product:
num = [1,2,3]
let = ["a","b","c"]
num.product let
#=>[[1, "a"], [1, "b"], [1, "c"], [2, "a"], [2, "b"], [2, "c"], [3, "a"], [3, "b"], [3, "c"]]
I have an array of arrays, like this:
aa = [ [a,d], [a,d1], [a,d], [b,d], [b,d2], [b,d3], [b,d2], [a,d2] ]
I would like to have a unique array of arrays, not just on the first element - which I can do by doing something like aa.uniq(&:first) - but rather remove the inner arrays if BOTH values match. So the result would be:
aa = [ [a,d], [a,d1], [a,d2], [b,d], [b,d2], [b,d3] ]
Can anyone assist in pointing me to an efficient way of doing this? I have large nr of arrays - in the order of 1 million - that I need to process.
Any help appreciated! John
If you need to maintain a collection of elements where each element is unique and their order is not important. You should use a Set. For instance,
require 'set'
my_set = Set.new
my_set << [1, 'a']
my_set << [1, 'a']
my_set << [1, 'b']
my_set.each { |elem| puts "#{elem}" }
It will give you
[1, "a"]
[1, "b"]
If the order is important, then use the uniq! on you array
aa.uniq!
If you want to get unique elements from an array, which will remove duplicate element, you can try this:
a = [[1, 2], [2, 3], [1, 2], [2, 3], [3, 4]]
a & a #=> [[1, 2], [2, 3], [3, 4]]
Try like this:
aa = [ ["a","d"], ["a","d1"], ["a","d"], ["b","d"] ]
aa.uniq
aa=[["a", "d"], ["a", "d1"], ["b", "d"]]
You missed double quotations ("). Inside of array, variables a, d, a, d1, etc. are strings. So, you should put them inside of double quotations ("").
I want an algorithm that gives one instance of a cycle in a directed graph if there is any. Can anyone show me a direction? In pseudo-code, or preferably, in Ruby?
I previously asked a similar question, and following the suggestions there, I implemented Kahn's algorithm in Ruby that detects if a graph has a cycle, but I want not only whether it has a cycle, but also one possible instance of such cycle.
example_graph = [[1, 2], [2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]
Kahn's algorithm
def cyclic? graph
## The set of edges that have not been examined
graph = graph.dup
n, m = graph.transpose
## The set of nodes that are the supremum in the graph
sup = (n - m).uniq
while sup_old = sup.pop do
sup_old = graph.select{|n, _| n == sup_old}
graph -= sup_old
sup_old.each {|_, ssup| sup.push(ssup) unless graph.any?{|_, n| n == ssup}}
end
!graph.empty?
end
The above algorithm tells whether a graph has a cycle:
cyclic?(example_graph) #=> true
but I want not only that but an example of a cycle like this:
#=> [[2, 3], [3, 6], [6, 2]]
If I were to output the variable graph in the above code at the end of examination, it will give:
#=> [[2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]
which includes the cycle I want, but it also includes extra edges that are irrelevant to the cycle.
I asked the same question in the math stackexchange site, and got an answer. It turned out that Tarjan's algorithm is good for solving this problem. I implemented it in Ruby as follows:
module DirectedGraph; module_function
## Tarjan's algorithm
def strongly_connected_components graph
#index, #stack, #indice, #lowlink, #scc = 0, [], {}, {}, []
#graph = graph
#graph.flatten(1).uniq.each{|v| strong_connect(v) unless #indice[v]}
#scc
end
def strong_connect v
#indice[v] = #index
#lowlink[v] = #index
#index += 1
#stack.push(v)
#graph.each do |vv, w|
next unless vv == v
if !#indice[w]
strong_connect(w)
#lowlink[v] = [#lowlink[v], #lowlink[w]].min
elsif #stack.include?(w)
#lowlink[v] = [#lowlink[v], #indice[w]].min
end
end
if #lowlink[v] == #indice[v]
i = #stack.index(v)
#scc.push(#stack[i..-1])
#stack = #stack[0...i]
end
end
end
So if I apply it to the example above, I get a list of strongly connected components of the graph:
example_graph = [[1, 2], [2, 3], [3, 4], [3, 5], [3, 6], [6, 2]]
DirectedGraph.strongly_connected_components(example_graph)
#=> [[4], [5], [2, 3, 6], [1]]
By selecting those components that are longer than one, I get the cycles:
DirectedGraph.strongly_connected_components(example_graph)
.select{|a| a.length > 1}
#=> [[2, 3, 6]]
And further if I select from the graph the edges whose both vertices are included in the components, I get the crucial edges that constitute the cycles:
DirectedGraph.strongly_connected_components(example_graph)
.select{|a| a.length > 1}
.map{|a| example_graph.select{|v, w| a.include?(v) and a.include?(w)}}
#=> [[[2, 3], [3, 6], [6, 2]]]
Depth first search, where you keep track of the visited vertices and the parent will give you the cycle. If you see an edge to a previously visited vertex then you have detected a cycle between your parent, yourself, and that vertex. A slight problem you may encounter is, if it is a cycle of length > 3, you'll only be able to tell the three vertices involved and will have to do some investigation into finding the rest of the vertices in the cycle.
For the investigation, you can start a breadth first search 'up' the tree starting from the parent and looking for the visited vertex, you should be able to find the whole cycle by doing that.
I have a bunch of objects in an array and would like to sort by a value that each object has. The attribute in question in each object is a numeric value.
For example:
[[1, ..bunch of other stuff],[5, ""],[12, ""],[3, ""],]
would become:
[[1, ..bunch of other stuff],[3, ""],[5, ""],[12, ""],]
I want to sort by the numerical value stored in each of the objects.
[5, 3, 4, 1, 2] becomes [1, 2, 3, 4, 5], however these numbers are stored inside objects.
The other answers are good but not minimal. How about this?
lst.sort_by &:first
The sort method can take a block to use when comparing elements:
lst = [[1, 'foo'], [4, 'bar'], [2, 'qux']]
=> [[1, "foo"], [4, "bar"], [2, "qux"]]
srtd = lst.sort {|x,y| x[0] <=> y[0] }
=> [[1, "foo"], [2, "qux"], [4, "fbar"]]
Assuming that you want to sort only according to the first element,
[[1, ..bunch of other stuff],[5, ""],[12, ""],[3, ""],].
sort_by{|n, *args| n}
or
[[1, ..bunch of other stuff],[5, ""],[12, ""],[3, ""],].
sort_by{|n, args| n}
When sorting objects and complex structures use sort_by. Sort_by performs a "Schwartzian Transform" which can make a major difference in sort speed.
Because you didn't provide enough information to be usable I'll recommend you read the docs linked above. You'll find its very easy to implement and can make a big difference.