I would like to write a code in Ruby that behaves like this C# code.
It receives a candidate topology set and a world set, and tests if the candidate topology is a topology in respect to the world.
In C# using LINQ features it looks like this:
public static bool IsTopology<T>(IEnumerable<IEnumerable<T>> candidate, IEnumerable<T> world)
{
IEqualityComparer<IEnumerable<T>> setComparer =
new SetComparer<T>();
if (!candidate.Contains(Enumerable.Empty<T>(), setComparer) ||
!candidate.Contains(world, setComparer))
{
return false;
}
var pairs =
from x in candidate
from y in candidate
select new {x,y};
return pairs.All(pair => candidate.Contains(pair.x.Union(pair.y), setComparer) &&
candidate.Contains(pair.x.Intersect(pair.y), setComparer));
}
public class SetComparer<T> : IEqualityComparer<IEnumerable<T>>
{
public bool Equals (IEnumerable<T> x, IEnumerable<T> y)
{
return new HashSet<T>(x).SetEquals(y);
}
public int GetHashCode (IEnumerable<T> obj)
{
return 0;
}
}
The features I am looking for are the following:
An ability to plug an equality comparer to methods
An ability to use nested maps (and anonymous types)
An ability to compare arrays as sets (not very important, in C# it lacks a bit...)
I believe that ruby has the features and am very interested to see how the equivalent code would look like.
I translated your code to ruby (and rewritten it a bit):
# candidate - Enumerable of Enumerable; world - Enumerable; &block - comparer of two sets.
def topology? candidate, world, &block
require 'set'
# you can pass block to this method or if no block passed it will use set comparison
comparer = block || lambda { |ary1,ary2| ary1.to_set.eql?(ary2.to_set) }
# create lambda-function to find a specified set in candidate (to reuse code)
candidate_include = lambda { |to_find| candidate.find {|item| comparer.(item, to_find) } }
return false if( !candidate_include.( []) || !candidate_include.( world) )
pairs = candidate.to_a.repeated_permutation(2)
pairs.all? do |x,y| x_set = x.to_set; y_set = y.to_set
candidate_include.(x_set & y_set) && # or x_set.intersection y_set
candidate_include.(x_set | y_set) # or x_set.union y_set
end
end
Hope this helps