compare values in datatable, change it if they are the same - c#

I want to check if under column "name" is there any same value. If yes so i want to check if the next same value > Bit + Size. I can do it with 2 for loops but what i want is something more simple.
Can anyone show me how?
My DataTable:
name Bit Size
m1 8 3
m0 9 5
m1 10 2 // Error, should be 11
m2 11 4
My code:
for(int i = 0; i <= Dt.Rows.Count - 1; i++)
{
for(int y = i +1; y <= Dt.Rows.Count - 1, y++ )
{
if(Dt.Rows[i]["name"].ToString() == Dt.Rows[y]["Name"].ToString())
if( (Convert.ToInt32(Dt.Rows[i]["Bit"].ToString()) + Convert.ToInt32(Dt.Rows[i]["Size"].ToString()) > (Convert.ToInt32(Dt.Rows[y]["Bit"].ToString()) ) )
{
// Show Error
MessageBox.Show("Error");
Dt.Rows[y]["Bit"] = Dt.Rows[i]["Bit"];
}
}
}

For what it's worth, this is the Linq approach:
var invalidGroups = DT.AsEnumerable()
.GroupBy(r => r.Field<string>("name"))
.Where(g => g.Count() > 1)
.Select(g => new { Name = g.Key, FirstRow = g.First(), Group = g })
.Select(x => new { x.Name, x.FirstRow, x.Group, FirstSum = x.FirstRow.Field<int>("Bit") + x.FirstRow.Field<int>("Size") })
.Where(x => x.Group.Any(r => x.FirstSum < r.Field<int>("Bit") + r.Field<int>("Size")));
foreach (var x in invalidGroups)
{
string name = x.Name;
DataRow referenceRow = x.FirstRow;
var invalidRows = x.Group
.Where(r => x.FirstSum < r.Field<int>("Bit") + r.Field<int>("Size"));
foreach (DataRow r in invalidRows)
{
int sum = r.Field<int>("Bit") + r.Field<int>("Size"); // 12 instead of 11
r.SetField("Bit", referenceRow.Field<int>("Bit"));
r.SetField("Size", referenceRow.Field<int>("Size"));
}
}
As you can see, it's not really shorter, but probably more maintainable or readable.

Try this in SQL
select b.name, b.bits + b.size
from Table_1 b
where exists (select name from Table_1 a where a.name = b.name group by name having count(*) > 1)
group by b.name, b.bits + b.size
having count(*) = 1

Related

select all rows that count of quantity fields least equal- Entity framework

I have Table like ProductInventory , In that I have some product with quantity .
I want select all rows where The least of a field equals to my input(number) .
I try with this :
List<product> Products = new List<product> {
new product{Id=1,Name="A",Quantity=1},
new product{Id=1,Name="A",Quantity=2},
new product{Id=1,Name="A",Quantity=3},
new product{Id=1,Name="B",Quantity=4},
new product{Id=1,Name="B",Quantity=7}
};
var result = Products
.AsEnumerable()
.GroupBy(r => r.Name)
.Where(g => (int)g.Sum(r =>r.Quantity)<= 4)
.ToList();
but it causes a return zero.
example:
I don't know is it possible in linq or not. But you can try this.
var result = Products.AsEnumerable().Where(g => g.Name == "A").ToList();
int userInput =4;
var total = 0;
var selectList = new List<product>();
for (int i = 0; i < result.Count; i++)
{
for (int j = i; j < result.Count; j++)
{
if (total + result[j].Quantity <= userInput)
{
total += result[j].Quantity;
selectList.Add(result[j]);
}
}
if (total == userInput)
break;
else
{
total = 0;
selectList = new List<product>();
}
}
if(userInput!=total)
selectList = new List<product>();
With that latest update, I think I finally understand what you are trying to do.
This won't work however, because you cant build the sum of booleans.
var result = Products
.AsEnumerable()
.GroupBy(r => r.Name)
.Where(g => g.Sum(r =>r.Quantity== 4))
.ToList();
What you actually want is
var result = Products
.GroupBy(r => r.Name)
.Where(g => g.Sum(r =>r.Quantity) >= 4) //or == 4 or whatever
.ToList();

Rename the Repeated Values in array c#

I have a array which looks like this :-
a[53]={ARPNUM-T,
OR1PATTYP-T,
IVNUM-T,
IVDESC-T,
ORDEPT-T,
ARPNAME-T,
ARGNAME-T,
ARPATADDR1-T,
ARPATCITY-T,
ARPATSTATE-T,
ARPATZIP-N,
ARSEX-T,
ARBIRTH-N,
ARSSN-T,
ARMARRY-T,
ARADMDT-N,
ARDISDT-N,
ARPEMP-T,
ARPHY1-T,
ARPHYNM1-T,
ARMRNUM-T,
ARGUARSSN-T,
ARPHONE-T,
AREMPLYR-T,
ARADDR1-T,
ARSTATE-T,
ARZIP-N,
ARPATPHONE-N,
ARDIAG01-T,
ISSUBNAME-T,
ISCOMPCD-T,
ISCONAME-T,
ISCONTRAC-T,
ISGROUP-T,
ISPRIMARY-T,
ISCOADDR-N,
ISCOCITST-T,
ISPATREL-T,
ISCERTNO-T,
ISCOZIP-N,
ISSUBNAME-T,
ISCOMPCD-T,
ISCONAME-T,
ISCONTRAC-T,
ISGROUP-T,
ISPRIMARY-T,
ISCOADDR-N,
ISCOCITST-T,
ISPATREL-T,
ISCERTNO-T,
ISCOZIP-N,
ARCITY-T}
There are some repeated values like ISSUBNAME-T,ISCOMPCD-T.
i need to fill the array a to array b
where repeated value will be suffixed by the number of times of repetition ,
For eg - if ISSUBNAME-T is repeated 3 times then ISSUBNAME-T_3 .
I have tried a code:-
for (int d = 1; d < 53; d++)
{
b[0] = a[0];
for (int k = 1; k < d; k++)
{
int count = 0;
//b[d] = a[d];
if (a[d] == a[d - k])
{
count++;
if (count > 0)
{
b[d] = a[d] + "_" + count + "";
}
else
{
b[d] = a[d];
}
//Console.WriteLine(count);
}
//Console.WriteLine(count);
}
//Console.WriteLine(count);
}
But it's not showing correct output.
Group array items by their values. Then check if group contains more than one item. If so, then return formatted item value, otherwise simply return item value:
string[] b = a.GroupBy(i => i)
.Select(g => g.Count() > 1 ?
String.Format("{0}_{1}", g.Key, g.Count()) : g.Key)
.ToArray();
Query syntax (easily allows to calculate group length only once):
var query = from i in a
group i by i into g
let count = g.Count()
select count > 1 ? String.Format("{0}_{1}", g.Key,count) : g.Key;
string[] b = query.ToArray();
UPDATE: If you want to keep all items and have incremental suffixes
string[] b = a.GroupBy(e => e)
.SelectMany(g => g.Count() == 1 ?
g.Take(1) :
g.Select((e,i) => String.Format("{0}_{1}", e,i+1))
.ToArray();
UPDATE 2: If you want also preserving original order, then simple loop and dictionary will be simpler
string[] b = new string[a.Length];
var duplicatedItems = a.GroupBy(a => a)
.Where(g => g.Count() > 0)
.ToDictionary(g => g.Key, g => g.Count());
for(int i = b.Length - 1; i >= 0 ; i--)
{
string item = a[i];
if (!duplicatedItems.ContainsKey(item))
{
b[i] = item;
continue;
}
b[i] = String.Format("{0}_{1}", item, duplicatedItems[item]);
duplicatedItems[item]--;
}
Linq query for comparison
string[] b =
a.Select((e,i) => new { Item = e, Index = i })
.GroupBy(x => x.Item)
.SelectMany(g => g.Count() == 1 ?
g.Take(1) :
g.Select((x,i) => new {
Item = String.Format("{0}_{1}", x.Item, i+1),
Index = x.Index
}))
.OrderBy(x => x.Index)
.Select(x => x.Item)
.ToArray();

How to Group by the sum of another Group by?

I am trying to do a Group By the sum of another Group By.
What is the correct way to do this in LINQ ?
The below query does not work but it is intended to demonstrate the logic I am tyring to achieve.
from so in TblServiceOrders
join sologs in TblSOLogs on so.SONumber equals sologs.SONumber
where so.DateClosed >= new DateTime(2014,01,17)
where so.DateClosed <= new DateTime(2014,01,17)
where sologs.ElapsedHours != 0 || sologs.ElapsedMinutes != 0
group new {sologs.ElapsedHours, sologs.ElapsedMinutes} by sologs.SONumber into g
group new {g.Sum (x => x.ElapsedHours), g.Sum (x => x.ElapsedMinutes)} by "Totals" into t
select new {
AverageHours = t.Average (x => x.ElapsedHours)
AverageMins = t.Average (x => x.ElapsedMinutes)
}
I've got the query working below. Now the next mystery is why I can't use it to populate a DataGridView in VS. :-(
Working Query:
from so in TblServiceOrders
join sologs in TblSOLogs on so.SONumber equals sologs.SONumber
where so.DateClosed >= new DateTime(2014,01,17)
where so.DateClosed <= new DateTime(2014,01,17)
where sologs.ElapsedHours != 0 || sologs.ElapsedMinutes != 0
group new {sologs.ElapsedHours, sologs.ElapsedMinutes} by sologs.SONumber into g
group new {hours = g.Sum (x => x.ElapsedHours), mins = g.Sum (x => x.ElapsedMinutes)} by "Totals" into t
select new {
Average = t.Average (x => (x.hours * 60) + x.mins),
Count = t.Count ()
}
Note the:
hours = g.Sum (x => x.ElapsedHours), mins = g.Sum (x => x.ElapsedMinutes)

Aggregate function Count() using dynamic linq query

I am trying to use Aggregate function Count() on some column using dynamic linq query but I am not able to achieve, what I am exactly looking is
Select Count(Id),Id
from Table1
Group By Id
Having Count(Id) > 1
I want to convert the same query to dynamic linq query, any suggestions on how to achieve this?
Stolen from here:
var distinctItems =
from list in itemsList
group list by list.ItemCode into grouped
where grouped.Count() > 1
select grouped;
The following two queries will give you the exact same result:
first with lambda second result without.
var Table1 = new List<Row>();
for (int i = 0; i < 10; i++)
{
for (int m = 0; m < 5; m++)
{
for (int x = 0; x < i + m; x++)
{
Table1.Add(new Row() { Id = m });
}
}
}
var result = Table1.GroupBy(row => row.Id)
.Where(p => p.Count() > 1);
var resultB = from row in Table1
group row by row.Id into rowGrouped
where rowGrouped.Count() > 1
select rowGrouped;
foreach (var r in resultB)
{
Console.WriteLine("ID {0} count: {1}", r.Key, r.Count());
}
May be something like this
list.GroupBy(item => item.Id)
.Where(group => group.Count() > 1)
.Select(group => new {
Id = group.Key,
Count = group.Count() });

Grouping each 500 elements of array according to array elements

I have an array of 2000 strings. The strings are: "art", "economy", "sport" and "politic". I want to group each 500 elements and get their counts
Could anyone help please?
Another solution:
var count = 0;
var dictionaries =
strings.GroupBy(s => count++ / 500)
.Select(g => g.Distinct().ToDictionary(k => k, k => g.Count(s => s == k)))
.ToList();
This will create a List<Dictionary<string, int>>. Each dictionary represents a tally of 500 elements (or possibly less for the last dictionary), where the keys are strings and the values are the number of occurrences of the string among the 500 elements the dictionary represents.
There is no requirement to hardcode all the possible values that may be encountered.
For the maximum possible performance you can also use this version:
var count = 0;
var dictionaries =
strings.GroupBy(s => count++ / 500)
.Select(g => g.Aggregate(
new Dictionary<string, int>(),
(d, w) => { d[w] = (d.ContainsKey(w) ? d[w] + 1 : 1); return d; })
)
.ToList();
This version iterates over each element in your source array exactly once. The output is in the same format as the first version.
var result = strings.Select((s, i) => new { s, i })
.GroupBy(x => x.i / 500)
.Select(x => x.GroupBy(y => y.s)
.Select(z => new {
Name=z.Key,
Count=z.Count()
}).ToList())
.ToList();
Try
var grouping = Enumerable.Range(0,2000)
.Select(i => i / 500)
.Zip(Strings, (i,s) => new { Group = i, Str = s})
.GroupBy(anon => anon.Group,
anon => anon.Str,
(key,g) => new
{
Key = key,
Art = g.Count(str => str == "art"),
Economy = g.Count(str => str == "economy"),
Politic = g.Count(str => str == "politic"),
Sport= g.Count(str => str == "sport")
});
foreach(anon in grouping)
{
//textbox logic OP will have to change to suit
TextBox1.WriteLine(String.Format("Group: {0}", anon.Key));
TextBox1.WriteLine(String.Format("Art: {0}",anon.Art));
TextBox1.WriteLine(String.Format("Economy: {0}",anon.Economy ));
TextBox1.WriteLine(String.Format("Politic: {0}",anon.Politic ));
TextBox1.WriteLine(String.Format("Sport: {0}",anon.Sport));
}
Alternatively (as per Snowbear)
var grouping = Strings.Select((s,i) => new { Group = i / 500, Str = s})
.GroupBy(anon => anon.Group,
anon => anon.Str,
(key,g) => new
{
Key = key,
Art = g.Count(str => str == "art"),
Economy = g.Count(str => str == "economy"),
Politic = g.Count(str => str == "politic"),
Sport= g.Count(str => str == "sport")
});
foreach(anon in grouping)
{
//textbox logic OP will have to change to suit
TextBox1.WriteLine(String.Format("Group: {0}",anon.Key + 1));
TextBox1.WriteLine(String.Format("Art: {0}",anon.Art));
TextBox1.WriteLine(String.Format("Economy: {0}",anon.Economy ));
TextBox1.WriteLine(String.Format("Politic: {0}",anon.Politic ));
TextBox1.WriteLine(String.Format("Sport: {0}",anon.Sport));
}
int CountElementsInGroup = 500;
//from 500 to 1000
int NumberGroup = 2;
string[] GroupTypes = new string[4] { "art", "economy", "sport", "politic" };
//Fill example array
string[] arr = new string[2000];
Random rand = new Random();
for (int i = 0; i < arr.Length;i++ )
arr[i] = GroupTypes[rand.Next(0, 3)];
var res = (from p in arr.Skip((NumberGroup - 1) * CountElementsInGroup).Take(CountElementsInGroup)
group p by p into g
select new GroupCountClass { GroupName = g.Key, GroupCount = g.Count() });
textBox1.Text = "";
foreach (GroupCountClass c in res)
{
textBox1.Text += String.Format("GroupName:{0} Count:{1};",c.GroupName,c.GroupCount);
}

Categories

Resources