3

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.

Marijn
  • 10,367
  • 5
  • 59
  • 80
Kobi
  • 33
  • 4
  • 1
    Your `GetHashCode()` is extremely slow. You should use `HashSet`s and http://msdn.microsoft.com/en-us/library/bb335475.aspx instead. – SLaks Nov 09 '11 at 19:25
  • If you are more familiar with .NET's LINQ and need to get this done urgently, you could use IronRuby, which allows you to mix Ruby and .NET code. If you have the time, though, learning to do this the Ruby way would be the way to go – dario_ramos Nov 09 '11 at 19:27

1 Answers1

3

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

Aliaksei Kliuchnikau
  • 13,589
  • 4
  • 59
  • 72