C# compare two Lists and update it's column values - c#

I've got two C# lists (List listA and List listB)
how can I compare these two and if duplicate (of specific columns ex. ID_num and ID_cust) is found then update column "ID_duplicate" which is value of listB's columns ID.
DataSet ds = subMain;
List<string> listA = (from r in ds.Tables[0].AsEnumerable()
Select r.Field<string>("ID_num") +
r.Field<string>("ID_cust")).ToList();
DataSet dsMain = Mains;
List<string> listB = (from r in dsMain.Tables[0].AsEnumerable()
select r.Field<string>("ID_num") +
r.Field<string>("ID_cust")).ToList();
I want that listA will contain new column ID_duplicate with value ID_num from listB.
So that duplicates will be somehow linked with this ID_num.
I will then update that ID_duplicate to database.
Edit:
Added more explanation in comment bellow.

If I understand is a join:
var listA = new List<Row> {
new Row { ID= 1, IdNum = 1, IdCust = 1 },
new Row { ID= 2, IdNum = 1, IdCust = 2 },
new Row { ID= 3, IdNum = 2, IdCust = 1 },
new Row { ID= 4, IdNum = 1, IdCust = 3 },
new Row { ID= 5, IdNum = 3, IdCust = 1 },
new Row { ID= 6, IdNum = 4, IdCust = 1 }
};
var listB = new List<Row> {
new Row { ID= 1, IdNum = 5, IdCust = 1 },
new Row { ID= 5, IdNum = 6, IdCust = 2 },
new Row { ID= 7, IdNum = 2, IdCust = 1 },
new Row { ID= 9, IdNum = 1, IdCust = 3 },
new Row { ID= 11, IdNum = 7, IdCust = 2 }
};
var t = (from a in listA
join b in listB on a.IdCust.ToString() + a.IdNum.ToString()
equals
b.IdCust.ToString() + b.IdNum.ToString()
select new
{
ID = a.ID,
IdUpdate = b.ID
}).ToArray();
foreach (var item in t)
{
Console.WriteLine("ID {0} IdUpdate {1}", item.ID, item.IdUpdate);
}
Here the Row class
class Row
{
public int ID { get; set; }
public int IdNum { get; set; }
public int IdCust { get; set; }
}
Obviusly you can create a calculated column on Row class like this
public string ValueToCompare
{
get
{
return this.IdNum.ToString() + this.IdCust.ToString();
}
}
and use this on join for comparison
Max

Related

Get the best selling product by using C# LINQ

I have a list of Receipts
IEnumerable<Receipt> Receipts =
new List<Receipt>()
{
new Receipt
{
Id = 1, CustomerId = 1, IsCheckedOut = false, OperationDate = new DateTime(2021, 1, 2),
ReceiptDetails = new List<ReceiptDetail>()
{
new ReceiptDetail { Id = 1, ProductId = 1, UnitPrice = 10, Product = ProductEntities.ElementAt(0), DiscountUnitPrice = 9, Quantity = 2, ReceiptId = 1 },
new ReceiptDetail { Id = 2, ProductId = 2, UnitPrice = 20, Product = ProductEntities.ElementAt(1), DiscountUnitPrice = 19, Quantity = 8, ReceiptId = 1},
new ReceiptDetail { Id = 3, ProductId = 3, UnitPrice = 25, Product = ProductEntities.ElementAt(2), DiscountUnitPrice = 24, Quantity = 1, ReceiptId = 1 },
}
},
new Receipt
{
Id = 2, CustomerId = 2, IsCheckedOut = false, OperationDate = new DateTime(2021, 1, 15),
ReceiptDetails = new List<ReceiptDetail>()
{
new ReceiptDetail { Id = 4, ProductId = 1, UnitPrice = 10, Product = ProductEntities.ElementAt(0), DiscountUnitPrice = 9, Quantity = 10, ReceiptId = 2 },
new ReceiptDetail { Id = 5, ProductId = 3, UnitPrice = 25, Product = ProductEntities.ElementAt(2), DiscountUnitPrice = 24, Quantity = 1, ReceiptId = 2 }
}
},
new Receipt
{
Id = 3, CustomerId = 1, IsCheckedOut = false, OperationDate = new DateTime(2021, 2, 15),
ReceiptDetails = new List<ReceiptDetail>()
{
new ReceiptDetail { Id = 6, ProductId = 1, UnitPrice = 10, Product = ProductEntities.ElementAt(0), DiscountUnitPrice = 9, Quantity = 10, ReceiptId = 3 },
new ReceiptDetail { Id = 7, ProductId = 2, UnitPrice = 25, Product = ProductEntities.ElementAt(1), DiscountUnitPrice = 24, Quantity = 1, ReceiptId = 3 }
}
}
};
I need to get the best selling(by quantity) products based on CustomerId
Here is my function
public IEnumerable<Product> GetMostSoldProductByCustomer(int customerId, int productCount)
{
var a = ReceiptEntities.Where(rd => rd.CustomerId == customerId)..SelectMany(x => x.ReceiptDetails);
var b = a.GroupBy(rd => rd.ProductId);
var c = b.Select(p => p.Select(y => y.Quantity).Sum());
}
I'm stuck on this, I have no idea how to connect b and c.
For better understanding, if customerId = 1 and productCount = 3. The function should return 3 products with Id = 1, 2, 3 accordingly in descending order by quantities
One note! The customer whose id = 1 has two receipts, that's why I'm calculating the sum of Quantity as there are the same products in different receipts
Try the following query:
public IEnumerable<int> GetMostSoldProductByCustomer(int customerId, int productCount)
{
var query =
from re in ReceiptEntities
where re.CustomerId == customerId
from rd in re.ReceiptDetails
group rd by rd.ProductId into g
select new
{
ProductId = g.Key,
TotalQuantity = g.Sum(x => x.Quantity)
} into s
orderby descending s.TotalQuantity
select s.ProductId;
return query;
}

Linq How to Join and get 2 tables values

I have 2 tables and i want to match up 2 Id values.
First table
Id - 1, 2, 3, 4, 5
DepartmentId - 2, 4, 5, 2, 1
Second table
Id- 1, 2, 10, 30, 40
I want to match up first table's Id's with second table's Id's so i can get DepartmentId values.
I need to get this virtual result:
Id- 1, 2, 10, 30, 40
DepartmentId -2, 4, null, null, null
Here is my code:
for (int i = 0; i < model1.Count(); i++)
{
model1[i].DepartmentId= model2.FirstOrDefault(k => k.Id== model1[i].Id).DepartmentId;
}
I get this error:
An exception of type 'System.NullReferenceException' occurred in
IYP.UserInterfaceLayer.dll but was not handled in user code
I think loop fails because of it can't find 10, 30, 40 Id values. If my Id values are same in 2 tables( Id = 1,2,3,4,5) loop works.
How can i do this with Linq?
You are basically looking for Left Join in LINQ. Try this:-
var query = from emp2 in Employee2
join emp1 in Employee1
on emp2.Id equals emp1.Id into allEmployees
from result in allEmployees.DefaultIfEmpty()
select new
{
ID = emp2.Id,
DeptID = result == null ? "No Department" : result.DepartmentId.ToString()
};
Where I have used following types:-
var Employee1 = new[]
{
new { Id = 1, DepartmentId = 2 },
new { Id = 2, DepartmentId = 4 },
new { Id = 3, DepartmentId = 5 },
new { Id = 4, DepartmentId = 2 },
new { Id = 5, DepartmentId = 1 },
};
var Employee2 = new[]
{
new { Id = 1 },
new { Id = 2 },
new { Id = 10 },
new { Id = 30 },
new { Id = 40 },
};
Complete Working Fiddle.
You should use the Join LINQ extension method. In the form of query syntax (which I believe is more readable for this case) it will look like:
var matchedValues =
from second in model2
join first in model1
on second.Id equals first.Id
into temp
from tempFirst in temp.DefaultIfEmpty()
select
new
{
second.Id,
DepartmentId = tempFirst == null ? null : tempFirst.DepartmentId
};
You join on the Id property and for any value you don't find in the model1, you use a default (DefaultIfEmpty call). Then you choose the resulting DepartmentId based on the join result.
try this
List<long> idlist=model2.tolist().select(t=>t.Id);
List<long> depIdList=model1.where(t=>idlist.contains(t.id)).toList();
I am going to assume that model1 and model2 are both IEnumerable. In that case the following should work.
var result = from x in model2
select
new Model1Type {DepartamentId = x,
Value=
model1.FirstOrDefault(y=>y.DepartamentId==x)
.Select(y=>y.Value)};
This is called Lamq :D
Hope this helps :)

How to select records with duplicate column by group using LINQ?

For some reason some records have the same ID. Aim is to list all the whole record which have the same ID. For example, how can group the following records by GroupId using LINQ, and find all records with the same ID and list them all? (thus merging all rows in each group into one)
var list = new List<Record>()
{
new Record() { GroupId = 0, ValueA = 20, ValueB = 300 },
new Record() { GroupId = 1, ValueA = 30, ValueB = 700 },
new Record() { GroupId = 1, ValueA = 40, ValueB = 500 },
new Record() { GroupId = 2, ValueA = 80, ValueB = 300 },
new Record() { GroupId = 2, ValueA = 20, ValueB = 200 },
new Record() { GroupId = 2, ValueA = 20, ValueB = 200 }
};
Expect result is the last 5 records.
Another way is:
var results = (from l in list
group new {l.ValueA, l.ValueB} by l.GroupId
into g
select new {GroupId = g.Key, Values = g.ToList()}).ToList();
If you prefer lambda expression, then
var results = (list.GroupBy(l => l.GroupId, l => new {l.ValueA, l.ValueB})
.Select(g => new {GroupId = g.Key, Values = g.ToList()})).ToList();
This should give you records based on unique GroupIdalong the other values associated.
EDIT
foreach (var result in results)
{
foreach (var value in result.Values)
{
int valueA = value.ValueA;
int valueB = value.ValueB;
}
}
I think you are looking for something similar to this.
Hope it helps.
Answer for "how can group the following records by GroupId using LINQ"
var groupList = list.GroupBy((mRecord) => mRecord.GroupId).ToList();
var groups = list.ToLookup(record => record.GroupId);
var groups1 = groups[1]; //all records with GroupId = 1

Group by using linq (range + count)

var data = new[] {
new { Id = 0, Cat = 1, Price = 2 },
new { Id = 1, Cat = 1, Price = 10 },
new { Id = 2, Cat = 1, Price = 30 },
new { Id = 3, Cat = 2, Price = 50 },
new { Id = 4, Cat = 2, Price = 120 },
new { Id = 5, Cat = 2, Price = 200 },
new { Id = 6, Cat = 2, Price = 1024 },
};
var ranges = new[] { 10, 50, 100, 500 };
Needed output is grouped price count by equal or greater than the range used according categories.
(in one linq statement)
cat range count
-------------------------------------
1 10 2 (In 1. categories there is 2 item that price >= 10(range) [10;30])
2 10 4 (In 2. categories there is 4 item that price >= 10(range) [50;120;200;1024])
2 50 4 ....
2 100 3 ....
2 500 1 (In 2. categories there is 1 item that price >= 500(range) [1024])
Try this:
var data = new[] {
new { Id = 0, Cat = 1, Price = 2 },
new { Id = 1, Cat = 1, Price = 10 },
new { Id = 2, Cat = 1, Price = 30 },
new { Id = 3, Cat = 2, Price = 50 },
new { Id = 4, Cat = 2, Price = 120 },
new { Id = 5, Cat = 2, Price = 200 },
new { Id = 6, Cat = 2, Price = 1024 },
};
var ranges = new[] { 10, 50, 100, 500 };
var result = from r in ranges
from g in data
where g.Price >= r
select new {g.Cat, Price=r};
var groupedData =
from d in result
group d by new{d.Cat, d.Price} into g
select new{Cat=g.Key.Cat, Price=g.Key.Price, TotalCount=g.Count()};
This should work:
var values =
data.SelectMany(x => ranges.Where(y => x.Price >= y)
.Select(y => new { Record = x, Range = y }))
.GroupBy(x => new { Cat = x.Record.Cat, Range = x.Range })
.Select(x => new { Cat = x.Key.Cat, Range = x.Key.Range, Count = x.Count()});
Results:
{ Cat = 1, Range = 10, Count = 2 }
{ Cat = 2, Range = 10, Count = 4 }
{ Cat = 2, Range = 50, Count = 4 }
{ Cat = 2, Range = 100, Count = 3 }
{ Cat = 2, Range = 500, Count = 1 }

Sub Totalling Relational Datatable

I have a datatable with relational data structure, I need to sum up the sub nodes to their parent nodes all the way up to the top parent (NULL parent Id)
I have attached 2 images which shows the original table and another with the expected results
Cheers
I've taken an approach that simulates data as they could have been materialized from a database by some ORM, i.e. a class that contains data and a collection of children. Plus some "business logic" to calculate the required numbers. So you can choose a db approach as well as an in-memory approach.
In Linqpad:
void Main()
{
var data = new[]
{
new Record { Id = 1, ParentId = null, Qty = 1, Cost = 0.0m },
new Record { Id = 2, ParentId = 1, Qty = 2, Cost = 0.0m },
new Record { Id = 3, ParentId = 1, Qty = 3, Cost = 0.0m },
new Record { Id = 4, ParentId = 2, Qty = 4, Cost = 0.0m },
new Record { Id = 5, ParentId = 3, Qty = 5, Cost = 0.0m },
new Record { Id = 6, ParentId = 2, Qty = 6, Cost = 1.7m },
new Record { Id = 7, ParentId = 4, Qty = 7, Cost = 1.8m },
new Record { Id = 8, ParentId = 5, Qty = 8, Cost = 1.9m },
new Record { Id = 9, ParentId = 5, Qty = 9, Cost = 2.0m },
}.ToList();
// Mimic ORM's job:
data.ForEach(d => d.ChildRecords =
data.Where(c => c.ParentId == d.Id).ToList());
data.Select(d => new { d.Id, d.Cost, d.TotalCost } ).Dump();
}
class Record
{
public int Id { get; set; }
public int? ParentId { get; set; }
public int Qty { get; set; }
private decimal _cost = 0m;
public decimal Cost
{
get { return this._cost + this.ChildRecords.Sum(cr => cr.TotalCost); }
set { this._cost = value; }
}
public decimal TotalCost
{
get { return this.Qty * this.Cost; }
}
public ICollection<Record> ChildRecords;
}
Result:
Id Cost TotalCost
1 619.2 619.2
2 60.6 121.2
3 166 498
4 12.6 50.4
5 33.2 166
6 1.7 10.2
7 1.8 12.6
8 1.9 15.2
9 2 18
An optimization could be to apply some memoization, i.e. let the Cost property store the result of its getter in a private member variable.

Categories

Resources