problem in using Distinct with Linq - c#

Hi have an issue with Linq. I have an array of double values with duplicate entries. I want to extract only distinct values from it. I have the following code which doesn't work correctly.
double[] dIds = GetIds(); //dIds has more than 10,000 items
var itemIdCollection = from id in dIds.Distinct()
select id;
Console.WriteLine(itemIdCollection.count().ToString()); //count is just 2 !!!!
Can you please give me a solution on this?
Thank you,

First off, you don't have to do that freaky select. Just call dIds.Distinct(). Second, I can guarantee you that it works on any array of doubles. Your doubles are NOT different from everybody else's doubles.
Obviously, if Distinct() is returning an enumerable of a count of 2 (btw, Console.WriteLine(itemIdCollection.Count()) is sufficient) it is because GetIds() returns an array containing only two distinct doubles.
Your assumptions, they are incorrect.

Try this:
List<double> x = new List<double>()
{
3, 4, 5, 6, 7, 7, 7, 8, 8
};
List<double> distinct = x.Distinct().ToList();
distinct.ForEach(y => Console.WriteLine(y));
Console.ReadKey();

Ghost debugging attempt:
Are you generating new random IDs in your GetIds() function? If so, remember you should be instantiating Random outside the function...

Related

I am trying to do get a list of random numbers which I want to not be repeated

I have a arraylist of names which get added 1 by 1. The range of the random number is the amount of people inside the arraylist.
For example:
NameList => [James, Vince, Joe, Joseph, John]
I want the output to be
NameListNum => [James 3, Vince 2, Joe 5, Joseph 1, John 4]
or
NameListNum => [James 2, Vince 5, Joe 1, Joseph 4, John 3]\
foreach (var name in nameList)
{
counter++;
int randomNum = rand.Next(Decimal.ToInt32(numOfShooters))+1;
nameListNum.Add(name + " "+randomNum);
foreach (var item in nameListNum)
{
}
}
Don't know if I am going in the right direction but the second foreach loop would be the one that checks the other nameListNum strings and regenerate a random number and rewrite it to the name.
Given that it is very easy to find the code to Shuffle a list of generated numbers randomly, the code is as easy as
var namesList = new []{"James", "Vince", "Joe", "Joseph", "John"};
var numsList = Enumerable.Range(1,namesList.Length).ToList().Shuffle();
var namesNumsList = namesList.Select( (n,i) => $"{n} {numsList[i]}").ToList();
Live example: https://dotnetfiddle.net/MzOwQa
If you want to randomise the names make them a List<string>:
var namesList = new List<string>{"James", "Vince", "Joe", "Joseph", "John"}.Shuffle();
The only other change is that you'll need namesList.Count on the following line in place of namesList.Length
Ok, let's go step by step. You have a list of names and you want to assign a unique random number to each name. The random numbers must be within the range [1, number of names in the list]
The naive brute force way would be to generate a random number, check if it has been rolled before and if not assign it to a name. Repeat the process for each name in the list in order and you are done.
With 4 or 5 names, this will actually run pretty fast but its wateful. Even more when lists get very big, getting to the point where its wasteful and performs horribly. Why? Well you need to roll many more times than necessary.
Is there a better way? Yes. Imagine you problem is: write a method that returns one by one random cards in a standard deck? Would you do it the same way? Or would you somehow store and ordered deck, shuffle it and then simply hand the cards out one by one?
Well, here its the same. Your standard deck is simply an ordered list of numbers from 1 to the total number of shooters: 1, 2, 3, ...., numberOfShooters.
Now, how would you shuffle it. Well, a naive way would be to create a list, then randomly pick an index, pick the number stored in that list and then remove it from the list to avoid rolling it again. That would work, but again, its wasteful. Why? Because repeatedly removing items in a list can be expensive. Remember lists are just wrappers over a standar array; removing an item mid list entails that all following numbers must be shifted un position up in the array.
An easy way to shuffle a list without all these problems is to use linq (there are better ways but this should suffice in your case):
var numbersToShuffle = Enumerable.Range(1, numberOfShooters);
var rnd = new Random();
numbersShuffled = numbersToShuffle.OrderBy(i => rnd.Next());
The rest should be easy.

Different kind of concatenate two arrays in c#

I have two lists posted from view to controller such as
int[] blablaIds = { 13, 377, 1002 };
int[] secondBlaBlaIds = { 7, 18, 126 };
For some reason I want to explicitly combine these as
int[] combinedIds = { { 7, 13 }, {18, 377}, {126, 1002} }
Is it possible with LINQ?
There's no such thing as a list of long or int you're going to have to pick one and then convert the other list to the correct datatype. Once they're the same datatype you can easily concat the two lists.
longIds.Concat(intIds.Cast<long>());
As Jon Skeet has identified in the comments your question is incredibly difficult to answer in its current form. If you're looking to create a paired list of items from the first and second you could try using .Zip. You're still going to have to do some casting if you want ints and longs to coexist in the same collection. Here's an example (not verified with IDE).
var zipped = firstIds.Zip(secondIds, (first, second) => new List<long> {first, (long) second});
Have a look at SelectMany. It's rather powerful and should provide the functionality you are looking for.

Does LINQ have any easy/elegant way to take the first element and put it at the end?

Or should I say, skip the first element and come back to it at the end.
e.g. say I have
int[] arr = { 2, 4, 3, 9, 1, 0 };
and want to iterate through it like
{ 4, 3, 9, 1, 0, 2 }
I know one way would be like
foreach(int i in arr.Skip(1).Append(new int[] { arr.First() }))
which is why I'm asking whether there's a better looking and/or more efficient way.
Only slightly cleaner than what you've got:
foreach(int i in arr.Skip(1).Concat(arr.Take(1)))
{
...
}
Another way. (not cleaner tho)
Enumerable.Range(1, arr.Length)
.Select(x => arr[x%arr.Length]);
I would hold it into a new collection, like a list, since it will be more ckear what I am doing when somebody else will read my code (if ever). A list is well optimized for this kind of behavior:
var list = arr.ToList();
list.Add(list.ElemntAt(0));
list.RemoveAt(0);
Then you can iterate the list, and it is more verbose to do it this way rather than using a Linq query, which can solve this problem, but it may not be so easy to read.

Getting a continuous chain of values based on a condition in LINQ

Say I have a List of numbers:
var list = new List<int>{100, 1, 2, 4, 10, 11, 50, 54};
And I want the output to be sets of numbers that satisfy a condition of "closeness" with its adjacent values.
So for example, if I define the distance between adjacent numbers to be less than 5, I will get something like:
Set1: {100}
Set2: {1, 2, 4}
Set3: {10, 11}
Set4: {50, 54}
Since the numbers in each set are within 5 of its adjacent value.
How would I do this in LINQ? I was thinking of some combination of Aggregate() and TakeWhile() but I couldn't figure it out.
To be clear, I am looking for a generic way of solving this (i.e. an algorithm that if I change 5 to any other number would also give an output of sets that satisfy the new condition).
I'm sure there are better approaches, since you want to do it with Linq you could do something like this.
int gid=0, prevvalue = list[0];
va result = list.Select(x=>
{
var obj = Math.Abs(prevvalue-x)>=10?
new {gid= ++gid, item =x}
:new {gid= gid, item =x};
prevvalue= x;
return obj;
})
.GroupBy(x=>x.gid)
.Select(x=>x.Select(s=>s.item).ToList())
.ToArray();
Check this Demo

Get array index values of the top 1000 largest entries inside an array using LINQ

I would like to have a nice clean LINQ code that can get an array of the index values of the top 1000 largest values inside an array.
For example:
int[] IndexArray = ArrayWithValues.Return_Indexes_Of_1000_Biggest_Values
The code is obviously bogus it is just to illustrate what I need.
UPDATE
I totally forgot to say that I need a second functionality. I have a second array, and I need to retrieve all the values in the second array which has the same indexes as contained inside the IndexArray.
I can do it easily using loops and all that but the code is big, and I want to learn to use LINQ more often but at the moment LINQ is still very foreign to me.
I have gone through similar questions asked here but I was not able to modify the code to suite my needs, since people usually only need the values and not the indexes of the values.
Thanks for the help!
Something like this should work. It uses the overload of Select that allows you to incorporate a second input that is the index of the item in the sequence.
var indexArray = sourceArray
.Select((value, index) => new { value, index })
.OrderByDescending(item => item.value)
.Take(1000)
.Select(item => item.index)
.ToArray();
Simply project the value and index into an object, order by the value, take the top 1000 items, and then select simply the indexes before converting to an array.
Testing by taking the top 5 indexes from the array { 10, 4, 6, 8, 2, 3, 5, 1, 9, 7 } yields { 0, 8, 3, 9, 2 }, which maps to values { 10, 9, 8, 7, 6 }.
As the comments have already addressed in regards to your update, you can simply take these indices to select from the other if you are confident the arrays are equal in length or will otherwise not result in an IndexOutOfBoundsException.
.Select(item => otherArray[item.index])
.ToArray();
Another method you could look up would be Enumerable.Zip.

Categories

Resources