I have a DataSet that contains a column, call it Type which contains ints. I'm using LINQ to manipulate the DataSet and I want to sort by Type. The Type column only contains 3 values right now (1, 2, 3). I would like to sort so that Type 2 are first in the list and then 1 and 3.
Is there an easy solution for this or am I going to have to customize the OrderBy?
Few solutions :
table.AsEnumerable()
.OrderBy(r => r.Field<int>("Type")==2 ? 0 : 1)
.ThenBy(r => r.Field<int>("Type"));
or probably better
table.AsEnumerable().
OrderBy(r => r.Field<int>("Type")==2
? 0
: r => r.Field<int>("Type"))
or also elegant Tim Schmelter's solution
table.AsEnumerable()
.OrderByDescending(r => r.Field<int>("Type")==2)
.ThenBy(r => r.Field<int>("Type"))
Advantage or Tim Schmelter's solution : you're not depending on a "pseudo-value".
In the two first solutions, we assert that 0 is ((min possible value of the field) -1).
Is this real, can it change, we don't know.
To make the sample simpler I removed the fact that we start from a DataTable, it's just a detail, and I thought we could do this:
var list = new [] { 1, 3, 5, 2, 4, 6, 9, 8 };
var sorters = new [] { 3, 2, -1 };
var o = from s in sorters
from l in list.OrderBy(x => x)
where s == l || (s == -1 && !sorters.Contains(l))
select l;
The sort array contains the preferred sorters, this way we can have more than one if we need them, and then there is a 'jolly' (-1) to represent the end of the sorters. The jolly could be handled in a better way, it's like that just to give you the idea. At this point the algorithm is generic and does not need any hard-coded check on the preferred values (just the jolly).
There are some potential inefficiencies, but I just wanted to show the general idea of this solution, with some more works it could be done more efficiently.
Here you have like 5 ways of accomplishing this. It's a post regarding how to set value as the first of the order, then throw in the ones lower, and after the ones higher than the selected so if you have {1 2 3 4 5 6} and select item 4, output: {4 1 2 3 5 6}.. I prefer my own answer though.. ^_^
https://stackoverflow.com/a/12580121/920359
Related
So i am new to c sharp and been playing around with my code but could not figure it out.
Let say i have the following:
Code : 2 1 1 1 1 2
Guess: 2 2 1 2 2 1
Firstly, ignore the spots where the guess matches the code. After that, only
2 2 2 1
will be left for the guess and
1 1 1 2
for the code
If you see for the rest of the code, there is three 2's for the guess but only one in the code. I want to count the three 2's as only one occurrence but the part of my code accounts for all 3 which i cant seem to get it working to count as one.
Here is my code. I only post the part im having trouble on.
if (guess.Contains(Code[i]))
{
if (guess.Distinct().Count() > 1)
diffSpot++;
}
I tried using distinct to get only unique numbers only and count to see that if its greater than 1 , it means there is dupe (same occurence in a row) but i guess im missing something. Thanks for any helpful hints and suggestions.
Liang,
Assuming that what you're after is this:
I kind of like LINQ for this:
using System.Linq;
int[] Code = {2, 1, 1, 1, 1, 2};
int[] Guess = {2, 2, 1, 2, 2, 1};
int total =
Guess.Select((g, i) => new {g, i})
.Where(x => x.g != Code[x.i])
.Select(x => x.g).Distinct().Count();
Returns 2.
Hope this helps.
I need to implement the following SQL in C# Linq:
SELECT NTILE (3) OVER (ORDER BY TransactionCount DESC) AS A...
I couldn't find any answer to a similar problem except this. However I don't think that is what I am looking for.
I don't even know where to start, if anyone could please give me at least a starting point I'd appreciated.
-- EDIT --
Trying to explain a little better.
I have one Store X with Transactions, Items, Units and other data that I retrieve from SQL and store in a object in C#.
I have a list of all stores with the same data but in this case I retrieve it from Analysis Services due to the large amount of data retrieved (and other reasons) and I store all of it in another object in C#.
So what I need is to order the list and find out if store X is in the top quartile of that list or second or third...
I hope that helps to clarify what I am trying to achieve.
Thank you
I believe that there is no simple LINQ equivalent of NTILE(n). Anyway, depending on your needs it's not that hard to write one.
The T-SQL documentation says
Distributes the rows in an ordered partition into a specified number of groups. The groups are numbered, starting at one. For each row, NTILE returns the number of the group to which the row belongs.
(see here)
For a very crude implementation of NTILE you can use GroupBy. The following example uses an int[] for sake of simplicity, but of course you are not restricted to
int n = 4;
int[] data = { 5, 2, 8, 2, 3, 8, 3, 2, 9, 5 };
var ntile = data.OrderBy(value => value)
.Select((value,index) => new {Value = value, Index = index})
.GroupBy(c => Math.Floor(c.Index / (data.Count() / (double)n)), c => c.Value);
First, our data is ordered ascending by it's values. If you are not using simple ints this could be something like store => store.Revenue (given you'd like to get the quantiles by revenue of the stores). Futhermore we are selecting the ordered data to an anonymous type, to include the indices. This is necessary since the indices are necessary for grouping, but it seems as GroupBy does not support lambdas with indices, as Select does.
The third line is a bit less intuitive, but I'll try and explain: The NTILE function assigns groups, the rows are assigned to. To create n groups, we devide N (number of items) by n to get the items per group and then device the current index by that, to determine in which group the current item is. To get the number of groups right I had to make the number of items per group fractional and floor the calculated group number, but admittedly, this is rather empirical.
ntile will contain n groups, each one having Key equal to the group number. Each group is enumerable. If you'd like to determine, if an element is in the second quartile, you can check if groups.Where(g => g.Key == 1) contains the element.
Remarks: The method I've used to determine the group may need some fine adjustment.
You can do it using GroupBy function by grouping based on index of the object. Consider a list of integers like this:-
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
You can first project the Index of all elements using Select and finally group by their resp. index. While calculating the Index we can divide it by NTILE value (3 in this case):-
var result = numbers.Select((v, i) => new { Value = v, Index = i / 3 })
.GroupBy(x => x.Index)
.Select(x => x.Select(z => z.Value).ToList());
Fiddle.
Here's my problem. I have one specific list, which I'll present as a int[] for simplicity's sake.
int[] a = {1,2,3,4,5};
Suppose I need to transform each item on this list, but depending on the situation, I may return an int or an array of ints.
As an example, suppose I need to return {v} if the value is odd, and {v,v+1} if the value is even. I've done this:
int[] b = a.SelectMany(v => v % 2 == 0 ? new int[] { v, v+1 } : new int[] { v })
.ToArray();
So if I run this, I'll get the expected response:
{1,2,3,3,4,5,5}
See that I have repeating numbers, right? 3 and 5. I don't want those repeating numbers. Now, you may tell me that I can just call .Distinct() after processing the array.
This is the problem. The SelectMany clause is fairly complex (I just made up a simpler example), and I definitely don't want to process 3 if it's already present in the list.
I could check if 3 is present in the original list. But if I got 3 in the SelectMany clause, I don't want to get it again. For instance, if I had this list:
int[] a = {1,2,3,4,5,2};
I would get this:
{1,2,3,3,4,5,5,2,3}
Thus returning v (my original value) and v+1 again at the end. Just so you can understand it better v+1 represents some processing I want to avoid.
Summarizing, this is what I want:
I have a list of objects. (Check)
I need to filter them, and depending on the result, I may need to return more than one object. (Check, used SelectMany)
I need them to be distinct, but I can't do that at the end of the process. I should be able to return just {v} if {v+1} already exists. (Clueless...)
One thing I thought about is writing a custom SelectMany which may suit my needs, but I want to be sure there's no built-in way to do this.
EDIT: I believe I may have mislead you guys with my example. I know how to figure out if v+1 is in a list. To be clear, I have one object which has 2 int properties, Id and IdParent. I need to "yield return" all the objects and their parents. But I just have the ParentId, which comes from the objects themselves. I'm able to know if v+1 is in the list because I can check if any object there has the same Id as the ParentId I'm checking.
ANSWER: I ended up using Aggregate, which can be used to do exactly what I'm looking for.
Does this simple loop with the HashSet<int> help?
int[] a = {1,2,3,4,5,2};
var aLookupList = new HashSet<int>();
foreach (int i in a)
{
bool isEven = i % 2 == 0;
if (isEven)
{
aLookupList.Add(i);
aLookupList.Add(i + 1);
}
else
{
aLookupList.Add(i);
}
}
var result = aLookupList.ToArray();
What about this using Aggregate method. You won't be processing numbers that are already in the list, wheather they were in the original list or as a result of applying (v + 1)
int[] v = { 1, 2, 3, 4, 5, 2 };
var result = v.Aggregate(new List<int>(),
(acc, next) =>
{
if (!acc.Contains(next))
return (next % 2 == 0) ? acc.Concat(new int[] { next, next + 1 }).ToList()
: acc.Concat(new int[] { next }).ToList();
else
return acc;
}).ToArray();
var existing = new HashSet<int>(a);
var result = existing
.Where(v => v % 2 == 0 && !existing.Contains(v + 1))
.Select(v => v + 1)
.Concat(existing)
.ToArray();
As I understand you have this input:
int[] a = {1,2,3,4,5};
And the output should also be {1,2,3,4,5} because you don't want duplicated numbers as you describe.
Because you use an array as input, you can try this code:
var output = a.SelectMany((x,i)=> x % 2 == 0 ? new []{x,x+1} :
i > 0 && a[i-1]==x-1 ? new int[]{} : new []{x});
//if the input is {1,2,4,5}
//The output is also {1,2,3,4,5}
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.
Given two arrays, I need to extract values from arrayB based on where the range(actual values) falls in arrayA.
Index 0 1 2 3 4 5 6 7 8 9 10 11 12
-------------------------------------------------------------
ArrayA = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 6}
ArrayB = {1, 0.2, 3, 4, 5, 6,5.5, 8, 9,11.1, 11, 12, 3}
Given the following ranges, I need to extract the following results
RangeToExtract* IndexInArrayA Expected Values To Extract
-------------- ------------- --------------------------
0 -> 1 [0,2] 1,0.2,3
1 -> 3 [3,6] 4,5,6,5.5
3 -> 5 [7,10] 5.5,8,9,11.1,11
1 -> 5 [3,10] 4,5,6,5.5,8,9,11.1,11
3 -> 10 [7,12] 8,9,11.1,11,12,3
* Refers to the actual values in ArrayA
Note: Given the RangeToExtract (0->1), determine the indexes in ArrayA where these values are, the result being (0->1) maps to [0,2] (The value 1 is in position 2 in ArrayA)
I only figured that the following special cases exists (not sure if there are more)
the lower limit is equal to zero and
when the upper limit does not exist in ArrayA
Further info:
Both arrays will be the same size
ArrayA will always be sorted
Code:
private double[] GetRange(double lower, double upper)
{
var myList = new double[ArrayA.Length];
var lowerIndex = Array.IndexOf(ArrayA, lower);
var upperIndex = Array.IndexOf(ArrayA, upper);
// special case 1
if (lowerIndex != 0)
{
lowerIndex = lowerIndex + 1;
}
// special case 2
if (upperIndex == -1)
{
upperIndex = ArrayA.Length-1;
}
for (int i = lowerIndex; i <= upperIndex; i++)
{
myList[i] = ArrayB[i];
}
return myList;
}
Given the above code, have all the special cases been taken into account? Is there a better way to write the above code?
Yap! There is a quite better way, that comes with lovely LINQ. I put here in two forms. First looks complicated but not at ALL! Believe me ;)
At the first step you have to take out those A'indexes that their values fall into your range (I call it min...max), based on your example I got that your range is closed from the lower boundary and closed on upper side, I means when you mentioned 3 -> 5 actually It is [3, 5)! It does not contain 5. Anyway that is not the matter.
This can be done by following LINQ
int[] selectedIndexes = a.Select((value, index) =>
new { Value = value, Index = index }).
Where(aToken => aToken.Value > min && aToken.Value <= max).
Select(t => t.Index).ToArray<int>();
The first select, generates a collection of [Value, Index] pairs that the first one is the array element and the second one is the index of the element within the array. I think this is the main trick for your question. So It provides you with this ability to work with the indexes same as usual values.
Finally in the second Select I just wrap whole indexes into an integer array. Hence after this you have the whole indexes that their value fall in the given range.
Now second step!
When you got those indexes, you have to select whole elements within the B under the selected Indexes from the A. The same thing should be done over the B. It means again we select B element into a collection of [Value, Index] pairs and then we select those guys that their indexes exist within the selected indexes from the A. This can be done as follow:
double[] selectedValues = b.Select((item, index) =>
new { Item = item, Index = index }).
Where(bToken => selectedIndexes.Contains(bToken.Index)).
Select(d => d.Item).ToArray<double>();
Ok, so first select is the one I talked about it in the fist part and then look at the where section that check whether the index of the bToken which is an element of B exists in the selectedIndexes (from A) or not!
Finally I wrap both codes into one as below:
double[] answers = b.Select((item, index) =>
new { Item = item, Index = index }).
Where(bTokent =>
a.Select((value, index) =>
new { Value = value, Index = index }).
Where(aToken => aToken.Value > min && aToken.Value <= max).
Select(t => t.Index).
Contains(bTokent.Index)).Select(d => d.Item).ToArray<double>();
Buy a beer for me, if it would be useful :)
I don't know if you're still interested, but I saw this one and I liked the challenge. If you use .Net 4 (having the Enumberable.Zip method) there is a very concise way to do this (given the conditions under futher info):
arrayA.Zip(arrayB, (a,b) => new {a,b})
.Where(x => x.a > lower && x.a < upper)
.Select (x => x.b)
You may want to use >= and <= to make the range comparisons inclusive.