Search rows with duplicate value in datatable - c#

I have this datatable (RadkyData):
Name EAN PRICE
ITEM1 12345 10
ITEM2 5558 55
ITEM3 12345 44
I need to search rows with duplicate value EAN.? (a list of all EAN that are duplicate)
I have this code:
var polozkySum = RadkyData.AsEnumerable()
.Select(r => new
{
c2 = r.Field<string>("EAN")
})
.GroupBy(g => new { g.c2 })
.Select(x => new
{
col2 = x.Key.c2
});
Have you any ideas please?

var rowsWithDupEAN = RadkyData.AsEnumerable()
.GroupBy(row => row.Field<string>("EAN"))
.Where(g => g.Count() > 1)
.SelectMany(g => g);
If you don't want the rows but only this column values(as mentioned in a comment):
var dupEanList = RadkyData.AsEnumerable()
.GroupBy(row => row.Field<string>("EAN"))
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToList();

You can use LINQ to DataTable.
var result = Radkydata.AsEnumerable()
.GroupBy(r => r.Field<string>("EAN"))
.Select(g => g.First())
.CopyToDataTable();

Related

What is the right way to show only group by column in datatable

I have below data in my Datatable
on above data, I'm filtering those records which are duplicate using below LINQ query
DataTable HasDuplicates = dt.AsEnumerable()
.GroupBy(g => g["Empolyee_CRC"])
.Where(c => c.Count() > 1)
.Select(g => g.OrderBy(r => r["Empolyee_CRC"]).First())
.CopyToDataTable();
Which returns me below data
Above data is successfully filtered but the issue which I'm facing is Budget_CRC column is not remove. So, for this I write below query and achieved my desire result.
DataTable HasDuplicates = dt.AsEnumerable()
.GroupBy(g => g["Empolyee_CRC"])
.Where(c => c.Count() > 1)
.Select(g => g.OrderBy(r => r["Empolyee_CRC"]).First())
.CopyToDataTable();
HasDuplicates.Columns.Remove("Budget_CRC");
HasDuplicates.AcceptChanges();
My question is how I get only one (Emplolyee_CRC) filtered column using my above LINQ query without writing below lines of code
HasDuplicates.Columns.Remove("Budget_CRC");
HasDuplicates.AcceptChanges();
You need to load another DataTable if you want your query to be returns DataTable
So use below query,
DataTable dtResult = new DataTable();
dtResult.Columns.Add("Empolyee_CRC");
DataTable HasDuplicates = dt.AsEnumerable()
.GroupBy(g => g["Empolyee_CRC"])
.Where(c => c.Count() > 1)
.OrderBy(x => x.Key)
.Select(g => dtResult.LoadDataRow(new object[] { g.FirstOrDefault().Field<string>("Empolyee_CRC") }, false))
.CopyToDataTable();
OR
DataTable HasDuplicates = dt.AsEnumerable()
.GroupBy(g => g["Empolyee_CRC"])
.Where(c => c.Count() > 1)
.OrderBy(x => x.Key)
.Select(g => dtResult.LoadDataRow(new object[] { g.Key }, false))
.CopyToDataTable();
Output:
Edit:
If you want to avoid creating new data table then you can simply project your selected data into list like.
In if below you can use any of both condition that separated with && or you can use as it is. depending upon your need.
if (dt.Rows.Count > 0 && dt.AsEnumerable().Select(x => x["Empolyee_CRC"]).Count() > 0)
{
var result = dt.AsEnumerable()
.GroupBy(g => g["Empolyee_CRC"])
.Where(c => c.Count() > 1)
.OrderBy(x => x.Key)
.Select(g => new { Empolyee_CRC = g.FirstOrDefault().Field<string>("Empolyee_CRC") })
.ToList();
}
Output:
It seems that you have wrong select statement in your LINQ, consider following example:
DataTable HasDuplicates = dt.AsEnumerable()
.GroupBy(g => g["Empolyee_CRC"])
.Where(c => c.Count() > 1)
.Select(g => g
.OrderBy(r => r["Empolyee_CRC"])
.Select(r => r["Empolyee_CRC"])
.First())
.CopyToDataTable();

Evenly distribute males and females in list with LINQ

I have Class1 like:
{
string Name,
string Sex
}
And I have a List<Class1> with 100 items where 50 are Males and 50 are Females, how do I get 10 groups of 5Males and 5Females each with LINQ?
I already manage to get the list grouped in 10 groups but not distributed evenly by sex.
var foo = My100List.Select((person, index) => new {person, index})
.GroupBy(x => x.index%10)
.Select(i => new Group
{
Name= "Group" + i.Key,
Persons= i.Select(y => y.person).ToList()
});
The code above don't distribute by sex.
Try this (untested):
int groupSize = 5;
var foo = My100List.GroupBy(x => x.Sex)
.SelectMany(g => g.Select((x, i) => new { Person = x, Group = i / groupSize}))
.GroupBy(x => x.Group)
.Select(g => new Group
{
Name = "Group" + g.Key,
Persons = g.Select(x => x.Person).ToList()
});
EDIT
Tested and confirmed. The above code works.
Add .OrderBy for sex before the .Select
Tested and working:
var foo = My100List.OrderBy(p => p.Sex).Select((person, index) => new {person, index})
.GroupBy(x => x.index%10)
.Select(i => new Group
{
Name= "Group" + i.Key,
Persons= i.Select(y => y.person).ToList()
});

Get duplicates from list case insensitive

List<string> testList = new List<string>();
testList.Add("A");
testList.Add("A");
testList.Add("C");
testList.Add("d");
testList.Add("D");
This query is case sensitive:
// Result: "A"
List<String> duplicates = testList.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToList();
How would it look case insensitive? (Result: "A", "d")
By using overloaded implementation of the GroupBy where you can provide the comparer required, e.g. StringComparer.OrdinalIgnoreCase:
var result = testList
.GroupBy(item => item, StringComparer.OrdinalIgnoreCase)
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToList();
By replacing
.GroupBy(x => x)
with
.GroupBy(x => x.ToLower())
you turn all string elements to lower case and group case insensitive.
var result = testList.GroupBy(x => x.ToLower())
.Where(g => g.Count() > 1)
.Select(g => g.Key)
.ToList();

c# lambda reading each row with GROUP BY and SUM

This is the working query i was using in my management studio.
SELECT TOP 5 productCode, SUM(productSales) AS sales
FROM sellingLog
WHERE (salesYear = '2014')
GROUP BY productCode
ORDER BY sales DESC
I want to convert the query above into lambda, but i can't seems to make it works. the lambda still lacks of order by and select the productCode
var topProducts = sellingLog
.Where(s => s.salesYear == 2014)
.GroupBy(u => u.productCode)
.Select(b => b.Sum(u => u.productSales)).Take(5)
.ToList();
foreach(var v in topProduct)
{
//reading 'productCode' and 'sales' from each row
}
var topProducts = sellingLog
.Where(s => s.salesYear == 2014)
.GroupBy(u => u.productCode)
.Select(g => new { productCode = g.Key, sales = g.Sum(u => u.productSales) })
.OrderByDescending(x => x.productCode)
.Take(5)
.ToList();
You can use the .Key with group by to get productCode
var topProducts = sellingLog
.Where(s => s.salesYear == 2014)
.GroupBy(u => u.productCode)
.Select(b => new {u.Key, b.Sum(u => u.productSales)}).Take(5)
.OrderByDescending(b=>b.Sales)
.ToList();

Adding more parameters to a Linq query

I'm using this query to count number of orders by date. I'm trying to add one more parameter that counts total products for each order, however I can't get it to work atm.
This is the essential part of a method that is suposed to return a list of 3 parameters (Date, TotalOrders and TotalProducts). Im using a Linq query to get a list with total order for each date, im wondering how to add my third parameter to the list "TotalProducts" and if i can do by adding one more search parameter in the Query. The foreach part below do not work propertly, it will return a list of TotalProducts but CreationDate will be the same for ech item in the list. I also have a feeling putting a foreach inside a foreach dosn't seem optimal for this:
var orders = _orderService.SearchOrderStatistics(startDateValue, endDateValue, orderStatus,
paymentStatus, shippingStatus, model.CustomerEmail, model.OrderGuid);
var result = orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new { Date = s.Key, Count = s.Count() });
List<GCOrdersModel> TotalOrdersPaid = new List<GCOrdersModel>();
foreach (var g in result)
{
foreach (var opv in orders)
{
GCOrdersModel _Om = new GCOrdersModel(g.Date, g.Count.ToString(), opv.OrderProductVariants.Count.ToString());
TotalOrdersPaid.Add(_Om);
}
}
return TotalOrdersPaid;
To access total products for every orders I must use OrderProductVariants.Count.ToString()
Can I add this parameter to the query?
Thx
You could try this:
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel()
{
Date = s.Key,
Count = s.Count(),
OpvCount = opv.OrderProductVariants.Count.ToString()
})
.ToList();
or
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel(s.Key, s.Count, opv.OrderProductVariants.Count.ToString()))
.ToList();
That way, you don't have to iterate over your result again. And it automatically creates your list of GCOrdersModel.
Edit
Does this work?
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel()
{
Date = s.Key,
Count = s.Count(),
OpvCount = s.OrderProductVariants.Count.ToString()
})
.ToList();
or
return orders.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new GCOrdersModel(s.Key, s.Count(), s.OrderProductVariants.Count.ToString()))
.ToList();
How about:
var opvCount =
opv
.OrderProductVariants
.Count
.ToString();
return
orders
.Where(o => o.PaymentStatus == PaymentStatus.Paid)
.GroupBy(g => g.CreatedOnUtc.Date.ToString("yyyyMMdd"))
.Select(s => new
{
Date = s.Key,
Count = s.Count()
})
.Select(x =>
new GCOrdersModelg(x.Date, g.Count.ToString(), opvCount));

Categories