1

If I have the following List

List<int> Values = new List<int>() { 1, 5, 6, 2, 5 };

and I want to check for duplicates, so I use GroupBy:

Values.GroupBy(x => x).Where(g => g.Count() > 1).Select(g => g.Key)

How do I make this work in a While conditional/convert to boolean so that, if and only if there are any duplicates present in Values, evaluate to true, otherwise, evaluate false using Linq? I suspect I need to use .Any somehow, but I'm not sure where to fit it in.

Erin W.
  • 51
  • 9
  • What is a "While conditional/convert to boolean "? – Enigmativity Oct 23 '17 at 05:27
  • What is the expected output – sujith karivelil Oct 23 '17 at 05:28
  • @Enigmativity The boolean that determines whether a while statement runs. IE, while (x > y) – Erin W. Oct 23 '17 at 05:29
  • @un-lucky It needs to evaluate to True if and only if Values contains any duplicate elements. Otherwise, evaluate to False. – Erin W. Oct 23 '17 at 05:30
  • @ErinW. - Then, I'm not following you on what you mean by "make this work in a While conditional/convert to boolean"? – Enigmativity Oct 23 '17 at 05:30
  • @ErinW. - What does "It needs to evaluate to True"? What is "It"? – Enigmativity Oct 23 '17 at 05:30
  • @Enigmativity if I paste that GroupBy linq into a while conditional, it errors because it's not a boolean. I need it to be a boolean that returns true if there are any duplicate elements to find in the list. – Erin W. Oct 23 '17 at 05:32
  • @ErinW. - Why would you put it in a `while` loop? That would imply that you are modifying the `Values` list inside the loop which cause the loop to throw an exception. What are you really trying to do? – Enigmativity Oct 23 '17 at 05:35
  • @Enigmativity In my project, I'm trying to use it in a do while loop. Inside the do, I generate a random number from 1 to 9, and add it to the Values list. if the number that gets generated is one already in the list, then run the loop over again. If not, escape the loop. – Erin W. Oct 23 '17 at 05:37
  • @ErinW. shuffle (also known as "unique random numbers") should not be implemented that way... - https://stackoverflow.com/questions/14473321/generating-random-unique-values-c-sharp, https://stackoverflow.com/questions/273313/randomize-a-listt – Alexei Levenkov Oct 23 '17 at 05:42
  • @ErinW. Why not simply check using Contains method before adding on the list and then proceed(Make life simpler) – Ipsit Gaur Oct 23 '17 at 05:44
  • @AlexeiLevenkov This is likely true, and I'm certainly open to suggestions. I'm still a newbie at this though and I'm just taking a crack at it. – Erin W. Oct 23 '17 at 05:44
  • @ErinW. - Are you trying to create a shuffled list of numbers so that there are no duplicates? – Enigmativity Oct 23 '17 at 05:55
  • @Enigmativity Yes! The project at large is a sudoku generator, so I need to make sure any values that already exist in the current row/column/box don't already exist. This do while loop happens inside of a foreach loop where I'm trying to assign a value to every TextBlock cell. – Erin W. Oct 23 '17 at 06:01
  • @ErinW. - I see. You're making your life hard with this approach. It'll slow down your computation dramatically. What you need to do is compute the possible values. If you need a value for a cell such that the value doesn't exist in the column, the row, and the current 9x9 grid (i.e. suddoku) then you simply do `Enumerable.Range(1, 10).Except(numbersInCurrentRow).Except(numbersInCurrentColumn).Except(numbersInCurrent9x9).ToList()`. If that list is empty then there are no possible numbers for that cell. If there are one or more then you have possible values for the cell. – Enigmativity Oct 23 '17 at 06:07
  • @Enigmativity That seems very simple, thank you. – Erin W. Oct 23 '17 at 06:10

3 Answers3

2

Simply check before adding randomly generated number in the list

do
{
    var randomNumber = //Generate number here

    if(!Values.Contains(randomNumber)) 
    {
        Values.Add(randomNumber);
        break;
    }

}while(true);
Ipsit Gaur
  • 2,872
  • 1
  • 23
  • 38
1

The root problem here, is that you are using a Select call. The Select call you are using will return an IEnumerable of longs, not a boolean.

The only way code like that would compile as part of a boolean (be it as a bool variable or as a check done inside an If, While, etc), is if you remove both the Select and the Where calls, and replace it with an Any:

List<int> Values = new List<int>() { 1, 5, 6, 2, 5 };

Values.GroupBy(x => x).Any(g => g.Count() > 1);

If you then need to find out what the duplicates actually are, then the best way to do this would be to store the results of the Group call in a variable, and then use that variable to call Any in your boolean check, and grab the items from the variable when you want to report on them:

List<int> Values = new List<int>() { 1, 5, 6, 2, 5 };    

var duplicateValues = Values.GroupBy(x => x).Where(g => g.Count() > 1);

bool anyDuplicates = duplicateValues.Any();

var duplicateKeys = duplicateValues.Select(x => x.Key).ToList();
Chris Thompson
  • 490
  • 5
  • 17
0

You can use combination of foreach loop and return value of HashSet<int>.Add method.
With this approach you don't need to loop all values if duplication have been found early. Where GroupBy should always loop all values.

public static bool HaveDuplicates(this IEnumerable<int> values)
{
    var set = new HashSet<int>();
    foreach (var value in values)
    {
        if (set.Add(value) == false)
        {
            return true;
        }
    }

    return false;
}

Use it as extension method

var values = new List<int>() { 1, 5, 6, 1, 2, 5, 6, 7, 8, 9 };
if (values.HaveDuplicates())
{
    // have duplicates
}

I'm trying to use it in a do while loop. Inside the do, I generate a random number from 1 to 9, and add it to the Values list. if the number that gets generated is one already in the list, then run the loop over again. If not, escape the loop

Use HashSet<T> for saving generated number. HashSet<T> will check for duplication with O(1) operations, where

var values = new HashSet<int>();
do
{
    var generatedValue = GenerateNumber(); // your generation logic

    if(values.Add(generatedValue) == false) 
    {
        break;
    }
}
while(yourCondition);

You can loop HashSet as other collections or convert it to List if you need

var numbers = values.ToList();
Fabio
  • 31,528
  • 4
  • 33
  • 72