convert nested for loop to linq with condition - c#

How to convert below c# nested for loop to linq...?
list = objBLForms.GetForms(Ids);
for (int i = 0; i < list.Count; i++)
{
for (int j = 0; j < list.Count; j++)
{
if (list[i].StateId == list[j].StateId &&
list[i].PayerId == list[j].PayerId && i != j)
{
if (string.IsNullOrEmpty(list[i].Tax))
{
list.Remove(list[i]);
}
else
{
list.Remove(list[j]);
}
}
}
}
I want to Remove duplicate payers with same state..And if any state tax is present, i wanted to remove the other duplicate one i,e; the duplicate one which is having no state tax...
I have achived it by using the nested for loop as shown above.
is there any way to do it in linq..I dont't know anything about linq.
Am very new to linq,Thanks in advance

The logic of your code is actually removing EVERYTHING that has string.IsNullOrEmpty(Tax), and only keeping first record that has value in Tax. Then, how about this
list
.Where(l => !string.IsNullOrEmpty(l.Tax))
.GroupBy(l => new {l.StateId, l.PayerId})
.Select(group => group.First())
.ToArray();

This seems about right to me:
list =
list
.OrderByDescending(x => x.Tax)
.GroupBy(x => new { x.StateId, x.PayerId })
.SelectMany(x => x.Take(1))
.ToList();

Related

How to check duplicate string array in list?

How to check duplicate string array in list?
I declare string array list like this:
List<string[]> list = new List<string[]>();
and I add a few items in the list.
list.Add(new string[3] {"1","2","3"});
list.Add(new string[3] {"2","3","4"});
list.Add(new string[1] {"3"});
list.Add(new string[1] {"3"});
list.Add(new string[3] {"1","2","3"});
now I want to get to know which items are duplicated. I tried like below to add the duplicated items to new list:
for (int j = 0; j < list.Count - 1; j++)
{
for (int k = list.Count - 1; k > j; k--)
{
if (j != k)
{
if (Enumerable.SequenceEqual(list[j], list[k]))
{
savedDistinctList.Add(list[j]);
}
}
}
}
and finally I want to remove the duplicated item in the first list. so I want to see 3 items in the list.([1,2,3],[2,3,4],[3])
Perhaps any idea using LINQ or something else?
First we have to teach .Net how to compare arrays:
private sealed class ArrayEqualityComparer<T> : IEqualityComparer<T[]> {
public bool Equals(T[] left, T[] right) {
if (ReferenceEquals(left, right))
return true;
if (left is null || right is null)
return false;
return left.SequenceEqual(right);
}
public int GetHashCode(T[] array) => array is null
? -1
: array.Length;
}
Then you can use Linq Distinct with this class implemented:
using System.Linq;
...
savedDistinctList = list
.Distinct(new ArrayEqualityComparer<string>())
.ToList();
If you want to modify the existing list, you can use HashSet<T>:
var unique = new HashSet<string[]>(new ArrayEqualityComparer<string>());
for (int i = list.Count - 1; i >= 0; --i)
if (!unique.Add(list[i]))
list.RemoveAt(i);
This has already been replied here: C# LINQ find duplicates in List by #Save
The easiest way to solve the problem is to group the elements based on their value, and then pick a representative of the group if there are more than one element in the group. In LINQ, this translates to:
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => y.Key)
.ToList();
If you want to know how many times the elements are repeated, you can use:
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(y => new { Element = y.Key, Counter = y.Count() })
.ToList();
This will return a List of an anonymous type, and each element will have the properties Element and Counter, to retrieve the information you need.
And lastly, if it's a dictionary you are looking for, you can use
var query = lst.GroupBy(x => x)
.Where(g => g.Count() > 1)
.ToDictionary(x => x.Key, y => y.Count());
This will return a dictionary, with your element as key, and the number of times it's repeated as value.
Apply with a foreach on your list.

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();

Having trouble iterating through a session key and comparing the value to database

Trying to iterate through a session key I have, collect the values into a list, and then compare it to a database.
I have tried:
List<Model> listVar = new List<Model>();
for(int i = 0; i < ids.Count; i++)
{
int index = arrayValue[i]
listVar = databasemodel.table.Where(s => s.id == index).ToList()
}
It's only grabbing one of the values though when I do this, kinda new to Linq. Is there a method I can use instead of what I am doing now?
I had a simlar issue before, I used the .Contains() method.. as follows:
.Where(s => id.Contains(s.id));
That should work.
Supposing the s.id is an integer then you need to add the results of your WHERE expression to the final list
var selectedids = new List<int>();
for(int i = 0; i < ids.Count; i++)
{
int index = arrayValue[i];
selectedIds.AddRange(databasemodel.table.Where(s => s.id == index));
}

Loop generates a lot of lines?

I cannot wrap my head around why this code generates a lot of null-lines:
int nr = 0;
foreach (var item in lists.Select(x => x.match_id))
{
foreach (var match in lists)
{
Console.Write(match.nickname
.Where(x => lists[nr].match_id == match.match_id)
.Select(z => match.nickname)
.FirstOrDefault());
}
nr++;
}
lists is an array of objects. The output:
Below all of the nulls are the next records, and then more nulls etc. Why?
To not output the null, you need to not call Console.Write if the value is null.
Try something like this:
int nr = 0;
foreach (var item in lists.Select(x => x.match_id))
{
foreach (var match in lists)
{
var n = match.nickname
.Where(x => lists[nr].match_id == match.match_id)
.Select(z => match.nickname)
.FirstOrDefault();
if (n != null)
{
Console.Write(n);
}
}
nr++;
}
You are looping twice through the same Array. I think you want to do:
for(int i = 0; i < lists.length; i++){
Console.Write(item.nickname
.Where(x=> lists[i].match_id === item.match_id)
.Select( z=> item.nickname)
.FirstOrDefault());
}
My 2 cents after a quick look..

Select top n rows in each group in EntityFramework

I'm trying to fetch recent contents of each type, currently I'm using something similar to the following code to fetch n records for each type
int n = 10;
var contents = Entities.OrderByDescending(i => i.Date);
IQueryable<Content> query = null;
for (int i = 1; i<=5; i++)
{
if (query == null)
{
query = contents.Where(c => c.ContentTypeIndex == i).Take(n);
}
else
{
query = query.Concat(contents.Where(c => c.ContentTypeIndex == i).Take(n));
}
}
One other solution can be creating an SP, but is it possible to do it by grouping in EF? If not, any cleaner solution?
contents.Where(c => c.ContentTypeIndex >= 1 && c.ContentTypeIndex <= 5)
.GroupBy(c => c.ContentTypeIndex)
.SelectMany(g => g.Take(n));
Note: if you want to select all types of indexes, then you don't need where filter here.

Categories

Resources