Linq query - List within List [duplicate] - c#

This question already has answers here:
Group by in LINQ
(11 answers)
Closed 5 years ago.
I'm trying to select a list that contains Fund.Name and List<Investment>.
var funds = new List<Fund>
{
new Fund { Id = 1 , Name = "good" },
new Fund { Id = 2, Name = "bad" }
};
var investments = new List<Investment>
{
new Investment { Fund = funds[0], Value = 100 },
new Investment { Fund = funds[0], Value = 200 },
new Investment { Fund = funds[1], Value = 300 }
};
Then I'm trying to create the query with this:
var query = from f in funds
join i in investments
on f.Id equals i.Fund.Id
select new { f.Name, i };
I wanted something like this:
{ Name = good, {{ Id = 1, Value = 100 }, { Id = 1, Value = 200 }}},
{ Name = bad, { Id = 2, Value = 300 }}
But I'm getting something like this:
{ Name = good, { Id = 1, Value = 100 }},
{ Name = good, { Id = 1, Value = 200 }},
{ Name = bad, { Id = 2, Value = 300 }}

Try using GroupJoin.
var query = funds.GroupJoin(investments, f => f.Id, i => i.Fund.Id, (f, result) => new { f.Name, result });

Related

Linq Pivot from SQL Query

I have problem with Linq, the code used to be processed in sql via stored procedure, but right now it supposed to be on code via linq, here's my database schema
SQL Fiddle
what I want is , from this data
orderNo
Type
serial
1
BN
BN 1
1
BE
BE 1
2
BN
BN 2
2
BE
BE 2
3
BN
BN 3
3
BE
BE 3
to be like this :
orderNo
be
bn
1
BE 1
BN 1
2
BE 2
BN 3
3
BE 2
BN 3
found one question and solution Source 1 - Stackoverflow , when I tried to my code, I got an issue with SelectMany
here's what I've tried
var results = data_tech.GroupBy(l => l.serial).SelectMany( g =>
new
{
Metadata = g.Key,
data = g
});
var pivoted = new List<PivotedEntity>();
foreach(var item in results)
{
pivoted.Add(
new PivotedEntity
{
Order= item.orderNo,
BE= item.data.Where(x => x.Name == "BE")
.FirstOrDefault().value,
BN= item.data.Where(x => x.Name == "BN")
.FirstOrDefault().value,
});
}
You can simply achieve this by changing the group by element serial to OrderNo. Let me give you an example,
var list = new List<Order>() {
new Order { orderNo = 1, Type = "BN", Serial = "BN 1" },
new Order { orderNo = 1, Type = "BE", Serial = "BE 1" },
new Order { orderNo = 2, Type = "BN", Serial = "BN 2" },
new Order { orderNo = 2, Type = "BE", Serial = "BE 2" },
new Order { orderNo = 3, Type = "BN", Serial = "BE 3" } ,
new Order { orderNo = 3, Type = "BE", Serial = "BN 3" } };
var results = list.GroupBy(l => l.orderNo).Select(g =>
new
{
Metadata = g.Key,
data = g
});
var pivoted = new List<PivotedEntity>();
foreach (var item in results)
{
pivoted.Add(
new PivotedEntity
{
Order = item.Metadata,
BE = item.data.Where(x => x.Type == "BE")
.FirstOrDefault().Serial,
BN = item.data.Where(x => x.Type == "BN")
.FirstOrDefault().Serial,
});
}
This will give you some output like this image.
Edit: Output PivotedEntity class =>
internal class PivotedEntity
{
public int Order { get; set; }
public string BE { get; set; }
public string BN { get; set; }
}

Join collections by id with linq [duplicate]

This question already has answers here:
Join/Where with LINQ and Lambda
(10 answers)
Closed 5 years ago.
I have a object collection
var myData = new[]
{
new {
ID = "1285",
COUNT = 45
},
new {
ID = "1286",
COUNT = 156
},
new {
ID = "1287",
COUNT = 965
}
};
And my another collection comes from another data source like this:
var incomingData = new[]
{
new {
ID = "1285",
LOCATION = "City-1"
},
new {
ID = "1286",
LOCATION = "City-2"
},
new {
ID = "1287",
LOCATION = "City-3"
}
};
I want to change incoming data with COUNT property by Id.
var NewData = new[]
{
new {
ID = "1285",
LOCATION = "City-1",
COUNT = 45
},
new {
ID = "1286",
LOCATION = "City-2",
COUNT = 156
},
new {
ID = "1287",
LOCATION = "City-3",
COUNT = 965
}
};
How can I do this with linq labda functions. I do not want to use foreach loop. (myData and incomingData collection lengths may be different)
Just use ordinary join statements like this:
var result=
(
from data in myData
join inData in incomingData
on data.ID equals inData.ID
select new
{
data.ID,
inData.LOCATION,
data.COUNT
}
).ToList();
Easy, simple, readable

Convert Objects into Hierarchy based on Number Sequence

I have following data Structure and i want to put covert it in a Hierarchy based on RelationId. This is sorted on RelationId.
Id = 2 has relationId =2 and following two rows has realtionId =0 . That represent the Id=3 and Id=4 are child of Id = 2
Id Name RelationId SortOrder
1 A 1 1
2 B 2 2
3 C 0 3
4 D 0 4
5 E 3 5
6 F 0 6
7 G 0 7
8 H 4 8
End Result would be like following
Id = 1
|
Id = 2
|___ Id = 3 , Id = 4
Id = 5
|___ Id= 6 , Id=7
Id = 8
The desired result is as following (for simplicity representing it as List). This would be a List<Something> in C#
Result =
[
{ Id = 1, Name = A, Children = Null },
{ Id = 2, Name = B, Children = [{ Id = 3, Name = C }, {Id = 4, Name = D }] },
{ Id = 5, Name = E, Children = [{ Id = 6, Name = F }, {Id = 7, Name = G }] },
{ Id = 8, Name = H}
]
My unsuccessful attempt is as following
var finalResult = new List<sampleDataClass>();
var sampleData = GetMeSampleData();
var count = sampleData.Count();
foreach (var item in sampleData)
{
var alreadyExist = finalResult.Any(x => x.Id == item.Id);
var newObject = new sampleDataClass();
if (!alreadyExist && item.RelationId!= 0)
{
newObject = item;
}
for (int i = item.SortOrder; i < count; i++)
{
if (sampleData[i].RelationId== 0)
{
newObject.Children.Add(sampleData[i]);
}
}
finalResult.Add(newObject );
}
Since your RelationId decides whether it is a root or nested element, you could form a group based on these relation and do this. I would suggest using Linq
List<SomeData> somedata = ... // your data.
int index=0;
var results = somedata
.Select(x=> new {gid = x.RelationId ==0? index: ++index, item=x})
.GroupBy(x=> x.gid)
.Select(x=> {
var first = x.FirstOrDefault();
return new
{
Id = first.item.Id,
Name = first.item.Name,
Children = x.Skip(1).Select(s=> new {
Id = s.item.Id,
Name = s.item.Name,
})
};
})
.ToList();
Output :
Id=1, Name=A
Id=2, Name=B
Id=3, Name=C
Id=4, Name=D
Id=5, Name=E
Id=6, Name=F
Id=7, Name=G
Id=8, Name=H
Check this Working Code
I have done it like this. Don't know if there can be some more elegant solution
var data = new List<MyDataObject>();
var SampleData = GetMeSampleData;
var count = SampleData.Count();
for (int i=0;i<count;i++)
{
var rootAdded = false;
var relationId = SampleData[i].relationId;
var alreadyExist = data.Any(x => x.Id == SampleData[i].Id);
var mydataObject = new MyDataObject();
if (!alreadyExist && SampleData[i].RelationId != 0)
{
mydataObject = SampleData[i];
rootAdded = true;
}
for(int j=i+1;j<count;j++)
{
if ((SampleData[j].RelationId == 0 && rootAdded))
{
mydataObject.Children.Add(SampleData[j]);
}
if (SampleData[j].SubjectId != 0)
break;
}
if (rootAdded)
{
data.Add(mydataObject);
}

At least one object must implement IComparable error in linq query

var pairs = new [] { new { id = 1, name = "ram", dept = "IT", sal = "3000" }, new { id = 2, name = "ramesh", dept = "IT", sal = "5000" }, new { id = 3, name = "rahesh", dept = "NONIT", sal = "2000" },
new { id = 5, name = "rash", dept = "NONIT", sal = "7000" } };
var query = from stud in pairs
where (stud.name.StartsWith("r") && stud.id % 2 != 0)
//orderby stud.sal descending
group stud by stud.dept into grps
select new { Values = grps, Key = grps.Key, maxsal=grps.Max() };
////select new { id = stud.id };
foreach (dynamic result in query)
{
Console.WriteLine(result.Key);
Console.WriteLine(result.maxsal);
foreach (dynamic result2 in result.Values)
{
Console.WriteLine(result2.id + "," + result2.sal);
}
}
Console.Read();
I am getting the error "At least one object must implement IComparable.", can someone explain me why iam I getting this error ?
You are calling grps.Max() to get maximnum item in group. Your anonymous objects are not comparable. How Linq will know which one is maximum from them? Should it use id property for comparison, or name?
I believe you want to select max salary:
maxsal = grps.Max(s => Int32.Parse(s.sal))

Select top N records after filtering in each group

I am an old bee in .NET but very new to Linq! After some basic reading I have decided to check my skill and I failed completely! I don't know where I am making mistake.
I want to select highest 2 order for each person for while Amount % 100 == 0.
Here is my code.
var crecords = new[] {
new {
Name = "XYZ",
Orders = new[]
{
new { OrderId = 1, Amount = 340 },
new { OrderId = 2, Amount = 100 },
new { OrderId = 3, Amount = 200 }
}
},
new {
Name = "ABC",
Orders = new[]
{
new { OrderId = 11, Amount = 900 },
new { OrderId = 12, Amount = 800 },
new { OrderId = 13, Amount = 700 }
}
}
};
var result = crecords
.OrderBy(record => record.Name)
.ForEach
(
person => person.Orders
.Where(order => order.Amount % 100 == 0)
.OrderByDescending(t => t.Amount)
.Take(2)
);
foreach (var record in result)
{
Console.WriteLine(record.Name);
foreach (var order in record.Orders)
{
Console.WriteLine("-->" + order.Amount.ToString());
}
}
Can anyone focus and tell me what would be correct query?
Thanks in advance
Try this query:
var result = crecords.Select(person =>
new
{
Name = person.Name,
Orders = person.Orders.Where(order => order.Amount%100 == 0)
.OrderByDescending(x => x.Amount)
.Take(2)
});
Using your foreach loop to print the resulting IEnumerable, the output of it is:
XYZ
-->200
-->100
ABC
-->900
-->800
This has already been answered but if you didn't want to create new objects and simply modify your existing crecords, the code would look like this alternatively. But you wouldn't be able to use anonymous structures like shown in your example. Meaning you would have to create People and Order classes
private class People
{
public string Name;
public IEnumerable<Order> Orders;
}
private class Order
{
public int OrderId;
public int Amount;
}
public void PrintPeople()
{
IEnumerable<People> crecords = new[] {
new People{
Name = "XYZ",
Orders = new Order[]
{
new Order{ OrderId = 1, Amount = 340 },
new Order{ OrderId = 2, Amount = 100 },
new Order{ OrderId = 3, Amount = 200 }
}
},
new People{
Name = "ABC",
Orders = new Order[]
{
new Order{ OrderId = 11, Amount = 900 },
new Order{ OrderId = 12, Amount = 800 },
new Order{ OrderId = 13, Amount = 700 }
}
}
};
crecords = crecords.OrderBy(record => record.Name);
crecords.ToList().ForEach(
person =>
{
person.Orders = person.Orders
.Where(order => order.Amount%100 == 0)
.OrderByDescending(t => t.Amount)
.Take(2);
}
);
foreach (People record in crecords)
{
Console.WriteLine(record.Name);
foreach (var order in record.Orders)
{
Console.WriteLine("-->" + order.Amount.ToString());
}
}
}

Categories