I have an unsorted list of ints:
1 3 1 2 4 3 2 1
I need to sort it, and before each group of equal numbers, insert a 0:
0 1 1 1 0 2 2 0 3 3 0 4
Is there a way to get from the first list to the second list with just one LINQ statement? I'm stuck at
from num in numbers
orderby num
select num
followed by a foreach loop that manually constructs the final output based on these results. I'd like to eliminate the second loop entirely, if possible.
Try:
list.GroupBy(n => n)
.OrderBy(g => g.Key)
.SelectMany(g => new[] { 0 }.Concat(g))
For each group of numbers, prepend 0, and then flatten the list with SelectMany.
And in query syntax:
from num in list
group num by num into groupOfNums
orderby groupOfNums.Key
from n in new[] { 0 }.Concat(groupOfNums)
select n
int[] nums = { 1, 3, 1, 2, 4, 3 ,2 ,1};
var newlist = nums.GroupBy(x => x)
.OrderBy(x=>x.Key)
.SelectMany(g => new[] { 0 }.Concat(g)).ToList();
Try this out on LinqPad.
var list = new int[]{1, 3, 1, 2, 4, 3, 2, 1};
var q = from x in list
orderby x
group x by x into xs
from y in (new int[]{0}).Concat(xs)
select y;
q.Dump();
This should give you the desired result.
Related
I have data like this
data
1 1 2 2 2 2 2 blank/ null 1 1 3 3 4 4 4 blank/ null blank/ null
Trying to get the base (total non blank rows) and percent column along with frequency.
So far Achieved to get this
Column Count
1 4
2 5
3 2
4 3
With this code
var result = data.GroupBy(x => x.Field<string>(xx), (row, l) => new Group { Column = row, Count = l.Count() })
I am trying groupby to get output something like this
Column Count Base Percent
1 4 14 28.57142857
2 5 14 35.71428571
3 2 14 14.28571429
4 3 14 21.42857143
Steps
Filter out unwanted entries (nulls)
Get the total count
Group your data
Project the data to your desired result
Like this
var data = new int?[] { 1, 1, 2, 2, 2, 2, 2, null, 1, 1, 3, 3, 4, 4, 4, null, null };
var filteredData = data.Where(x => x != null);
var totalCount = filteredData.Count();
var groups = filteredData.GroupBy(x => x);
var result = groups.Select(x => new { Value = x.Key, Count = x.Count(), Percent = x.Count() * 100.0 / totalCount });
Note: a group is a collection of the grouped items plus a key. The key is whatever your chose to group by. In this example, the key is an int. And because the group is a collection you can do stuff like .Count() on it.
Given the following dataset:
WharehouseId Sku OnHold InStock
===========================================
1 ABC-123 N 20
2 ABC-123 N 13
3 ABC-123 Y 4
4 ABC-123 N 18
I need to create an int[] array that returns the InStock items, but the value should be 0 if OnHold equals 'Y'. So in the dataset above, the array result should be:
{ 20, 13, 0, 18 }
I am able to accomplish this by the following:
int[] inStockQty = new int[4];
int i = 0;
foreach (var item in query)
{
inStockQty[i] = item.OnHold == 'N' ? item.InStock : 0;
i++;
}
But I'm wondering if there is also a way to do this using LINQ's ToArray()?
You can move the conditional into LINQ's Select, like this:
var inStockQty = query.Select(item => item.OnHold == 'N' ? item.InStock : 0).ToArray();
I want to sort a large integer array into 2 groups, i.e. 1 group the multiples of 4 and the other group the multiples of 5. How can I do this using just one query? Keep an eye on the performance which is really important in my case.
To further explain what I need, suppose my list of numbers is { 2, 7, 8, 10, 12, 14, 19,20, 25} then I would expect my output to be this:
new[]
{
new
{
Remainder = 4,
Numbers = new List<int>(){ 8, 12, 20}
},
new
{
Remainder = 5,
Numbers = new List<int>(){10, 20, 25}
}
}
Here's what I have gotten so far:
var numberGroupsTimes5 =
from n in numbers
group n by n % 5 into g
where g.Key == 0
select new { Remainder = g.Key, Numbers = g };
var numberGroupsTimes4 =
from n in numbers
group n by n % 4 into g
where g.Key == 0
select new { Remainder = g.Key, Numbers = g };
As you can see it gets me close with 2 queries but as I said I would like a single query.
You could use Concat:
var something = numberGroupsTimes5.Concat(numberGroupsTimes4);
to simply concatenate two sequences.
It's not entire clear why you use a GroupBy, then filter for Key == 0. Remainder will always be 0.
Maybe a simple Where is enough?
You can simply "combine" your queries by using a logical OR (||):
var something = numbers.Where(x => x%4 == 0 || x%5 == 0);
In response to your comment: Are you looking for something like this?
var result = new[] {4, 5}
.Select(d => new
{
Divider = d,
Values = numbers.Where(n => n % d == 0).ToList()
});
Do you mean?
var numberGroupsTimes4or5 = from n in numbers
group n by n into g
where g.Key % 4 == 0 || g.Key % 5 == 0
select new { Remainder = g.Key, Numbers = g };
Maybe this?
var result = new[] { 4, 5 }
.SelectMany(x => numbers.Select(n => (n, x)))
.Where(g => g.n % g.x == 0)
.GroupBy(g => g.x, (Key, g) =>
new { Remainder = Key, Numbers = g.Select(z => z.n) });
which gives this result
Here is a similar approach but this time using a query syntax like in your question.
var numbersAndRemainders = new[] { 4, 5 }
.SelectMany(rem => numbers.Select(n => (n, rem)));
var numberGroups =
from n in numbersAndRemainders
group n by new { remainder = n.n % n.rem, n.rem } into g
where g.Key.remainder == 0
select new { Remainder = g.Key.rem, Numbers = g.Select(z => z.n) };
There are two LINQ methods you could use for this:
//This will join the lists, excluding values that already appear once
var result = numberGroupsTimes5.Union(numberGroupsTimes4)
//This will simply append one list the the other
var result = numberGroupsTimes5.Concat(numberGroupsTimes4)
I have an array of lists:
private List<int>[] Graph = new List<int>[n];
For example:
Graph[0] = new List<int>() { 1, 2 };
Graph[1] = new List<int>() { 0 };
Graph[2] = new List<int>() { 0, 1, 3, 4 };
Graph[3] = new List<int>() { 2, 4, 1 };
Graph[4] = new List<int>() { 2, 3 };
Graph[0].Count // give 2
Graph[1].Count // give 1
Graph[2].Count // give 4
Graph[3].Count // give 3
Graph[4].Count // give 2
And I want to get an array (or list) which includes the indexes of the lists sorted by the count of the elements in each list. So for this example it will be:
orderList[0] -> 2 //(because Graph[2].Count give 4)
orderList[1] -> 3 //(because Graph[3].Count give 3)
orderList[2] -> 0 //(because Graph[0].Count give = 2)
orderList[3] -> 4 //(because Graph[4].Count give = 2)
orderList[4] -> 1 //(because Graph[1].Count give = 1)
orderList is an n-elements array.
You can use the select method that incorporates an index to combine the list count with the index
int[] orderList = Graph.Select((list, index) => new { Count = list.Count, Index = index }).OrderByDescending(a => a.Count).Select(a => a.Index).ToArray();
More readable query syntax
int[] orderList = (from pair in Graph.Select((list, index) => new { Count = list.Count, Index = index })
orderby pair.Count descending
select pair.Index).ToArray();
All you need is:
Graph = Graph.OrderByDescending(x => x.Count).ToArray();
You can use LINQ:
List<int>[] orderedGraph = graph.OrderByDescending(x => x.Count).ToArray();
This will order array descending using list "count" property.
Remember to add using:
using System.Linq;
I have a list using this Linq query
filterEntities = (from list in filterEntities where list.Id== 0 && list.Id== 1 && list.Id == 3 && list.Id== 6 select list).OrderBy(r => r.Id).ToList();
Now this linq returns a list like
ID Age
0 18
0 19
1 21
3 24
6 32
6 08
I want to generate a list using sum of same Id's which returns like
ID Age
0 37
1 21
3 24
6 40
Please suggest me possible query
I think you are looking to use a group by like this
List<int> ids = new List<int>() { 0, 1, 3, 6 };
filterEntities = (from list in filterEntities
where ids.Contains(list.Id)
group list by list.id into g
orderby g.Key
select new
{
ID = g.Key,
Age = g.Sum(x => x.Age),
}).ToList();
I would clean up the query like this, because the long expression looks a bit confusing:
var idList = new List<int> { 0, 1, 3, 6};
filterEntities = from e in filterEntities
where idList.Contains(e.Id)
group e by e.Id into g
select new { Id = g.Key, Sum = g.Sum(e =>e.Age) };
filterEntities = filterEntities.Where(l=>new[] { 0, 1, 3, 6 }.Contains(l.Id))
.Sum(c=>c.Age)
.GroupBy(r=>r.Id)
.ToList();