0

I'm trying to use a lambda expression to compare each element in a hashset to all of the others.

Here is an example of what I am trying to do. I have a class of type Implication. Implication has two properties - antecedent and consequent. If one implication says that A implies B and another says that B implies C, then there is a transitive relationship. In other words A implies C. Here is a simplified version of my code.

I'm trying to use a lambda expression to find all of the Implication objects within a hashset that have transitive relationships. In the last line of code in this class, I am using a Where clause to do the query. But, I'm getting error message. For some reason, it expects my second parameter (otherImplication) to be of type int instead of Implication. But, the first parameter is interpreted correctly. How do I tell it what type the second parameter is?

public class Implication
{
    public int antecedent  { get; set; }
    public int consequent  { get; set; }

    public Implication(int antecedent, int consequent)
    {
        this.antecedent  = antecedent;
        this.consequent  = consequent;
    }

    public static void Test()
    {
        HashSet<Implication> hashset = new HashSet<Implication>();
        hashset.Add(new Implication(1, 2));  //transitive
        hashset.Add(new Implication(2, 3));  //transitive
        hashset.Add(new Implication(3, 4));  //transitive
        hashset.Add(new Implication(5, 6));  //NOT transitive
        hashset.Add(new Implication(7, 8));  //NOT transitive

        var transitives = hashset.Where((implication, otherimplication) => implication.antecedent  == otherimplication.consequent);

        // I'm getting the following error message for 
        // 'otherimplication.consequent' at the end of the previous line.

        // Error CS1061  'int' does not contain a definition for 
        // 'consequent' and no extension method 'consequent' 
        // accepting a first argument of type 'int' could be 
        // found(are you missing a using directive or an 
        // assembly reference ?)    

    }
}

Thanks for your help.

Mikutus
  • 83
  • 1
  • 10
  • `Where` is not used to compare elements rather it's to filter a sequence. specifically this version of `Where` takes a given element from the sequence and its index hence the second argument is an `int`. – Ousmane D. Dec 27 '18 at 22:57
  • "_How do I tell it what type the second parameter is?_" That's not how programming works in .NET. The method defines what parameters it wants/need (as part of its method declaration). The purpose of each parameter is explained in the documentation for the respective method (if such a documentation hopefully exist). You are not going to tell a method what you think a parameter should be. The method will expect (or perhaps "demand") from you to provide meaningful and valid parameter arguments according to the method's declaration and documentation... –  Dec 27 '18 at 22:57
  • as @elgonzo pointed out [here](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.where) is the documentation on the Extension Method 'Enumerable.Where()' – Shimon Lebovits Dec 27 '18 at 23:02
  • Just a small comment - unless your class `Implication` overrides `Equals` and `GetHashCode` there is very little benefit in using `HashSet`. You might as well use `List`. – Enigmativity Dec 27 '18 at 23:40
  • 1
    Do you consider the following sequence transitive, (1,4),(2,3),(4,5),(5,2),(3,6) ? – TheGeneral Dec 28 '18 at 00:17
  • 2
    It's not clear what the expected output should be. Do you want all possible transitive groups? What about just `(1, 2), (2, 3)`? Is that considered transitive (even though `(1, 3)` is not explicitly in the list? And what about the comment by @TheGeneral above? Would that be a single group of transitive items, or do you want all the different implicit transitive items displayed as well (i.e. `(1, 5), (1, 2), (1, 3), (1, 6), (4, 2), etc...`) – Rufus L Dec 28 '18 at 00:33

1 Answers1

1

Try this:

    var antecedents = hashset.ToLookup(x => x.antecedent);
    var consequents = hashset.ToLookup(x => x.consequent);

    var transitives =
        hashset
            .Where(x =>
                antecedents[x.consequent]
                    .Concat(consequents[x.antecedent])
                    .Any());

That gives me (1, 2), (2, 3), (3, 4).

Enigmativity
  • 113,464
  • 11
  • 89
  • 172