0

This is what I did so far:

class CardDisplayer
{
    public int CardSuit;
    public int CardValue;
}

List<CardDisplayer> _playerHand;

// Group all cards by the same suit
var _handDuplicates = _playerHand.GroupBy(x => x.CardSuit)
                                .Select(g => g.ToList())
                                .ToList();

CardDisplayer _duplicateFound = null;

// And then find all cards with the same value number
for (int i = 0; i < _handDuplicates.Count; i++)
{
    var _handReference = _handDuplicates[i];

    var _temp = _handReference.GroupBy(x => x.CardValue)  
                                        .Where(g => g.Count() > 1)
                                        .Select(g => g.ToList())
                                        .ToList();
    // If you find more than one card with the same number
    if(_temp.Count > 0)
    {
        // Take it
        _duplicateFound = _temp.First().First();
        
        break;
    }    
}

What I'm trying to achieve is after get the player's hand I want to find if the player has duplicates in his hand by looking if there is cards with the same suit and the same value.

I tried a lot of things on the internet but I cannot figure out how to get the list of duplicates using LINQ instead write all these lines of code.

Can someone know how to do it please? Thank you.

Matthew
  • 149
  • 2
  • 11
  • 1
    Your for loop is effectively a .Select or a .ForEach on _handDuplicates, so you could chain those together if you wanted to? – Rup Jul 17 '20 at 12:45
  • 1
    Can you be more specific, please? – Matthew Jul 17 '20 at 12:47
  • 1
    Do you know how to use anonymous types to `GroupBy` multiple properties in one call? – mjwills Jul 17 '20 at 12:49
  • 1
    If you wanted to compare multiple properties at once you should probably enhance your CardDisplayer class to support it, e.g. add GetHashCode and Equals implementations, and write an IComparable for it. Then you could detect duplicates by added cards to a set, and duplicate cards would already exist at the point you tried to add them. – Rup Jul 17 '20 at 12:54
  • Like this answer? https://stackoverflow.com/questions/41428128/group-by-using-anonymous-type-in-linq – Matthew Jul 17 '20 at 13:05

2 Answers2

2

you can use the GroupBy method to create a complex key, then use the Any method to find if at least on group has more then 1 object, or Where / FirstOrDefault to find the duplicates

var grouped = _handReference.GroupBy(g => new {suit=g.CardSuit, value=g.CardValue});

var hasDuplicates=grouped.Any(g=>g.Count()>1);
var duplicateList=grouped.Where(g=>g.Count()>1);
var duplicate=grouped.FirstOrDefault(g=>g.Count()>1);
michael berezin
  • 1,146
  • 7
  • 8
1

After a while, I found the perfect solution based also on the answers.

        // Get the reference for the player hand
        List<List<CardDisplayer>> _playerHand = playersSlots[_playerIndex];

        // Find in the player's hand duplicates
        var _duplicates = _playerHand.GroupBy(x => new { x.CardSuit, x.CardValue })
                                        .Where(x => x.Skip(1).Any())
                                        .SelectMany(g => g)
                                        .Distinct(new CardEqualityComparer()) // Use this only if you want unique results
                                        .ToList();

        var _duplicateCard = _duplicates.FirstOrDefault();

If you want unique results you can use a custom CardEqualityComparer class and use it with the Distinct of LINQ

/// <summary>
/// Used to compare if two cards are equals.
/// </summary>
class CardEqualityComparer : IEqualityComparer<CardDisplayer>
{
    public bool Equals(CardDisplayer x, CardDisplayer y)
    {
        // Two items are equal if their keys are equal.
        return x.CardSuit == y.CardSuit && x.CardValue == y.CardValue;
    }

    public int GetHashCode(CardDisplayer obj)
    {
        return obj.CardSuit.GetHashCode() ^ obj.CardValue.GetHashCode();
    }
}

You can find the reference on the web: StackOverflow and DotNetPerls

Thank you, everyone, for the help.

Matthew
  • 149
  • 2
  • 11