Get count of same value on table - c#

I have this class where the query must result in this list a property.
This property must check on table how many duplicated exists.
This code works, but its very slow. can you help me ?
var lst = _uow.Repository.GetAll();
var query =
from p in lst
select new GetRfqResponse
{
ID = p.ID,
//bad performance
Count = lst.Where(x => x.Property == p.Property).AsQueryable().Count(),
//
};

Counting in a queryable list can be easily achieved using the Count() function:
// Find duplicated names
var byName = from s in studentList
group s by s.StudentName into g
select new { Name = g.Key, Count = g.Count() };
Check this fiddle to see it running.

Below is for InMemory
GroupBy should come to help.
var propertyGroupedList = list.GroupBy(l=>l.Property);
var query = list.Select(l => new GetRfqResponse{
Id = l.Id,
Count = propertyGroupedList.First(g=> g.Key == l.Property).Count()
});
Or you can create a dictionary with key as "Property" and value as count, then you will have to loop just once to store the count.
This allows you to get count in constant time
Dictionary<string, int> map = new Dictionary<string, int>();
foreach (var item in lst)
{
if (!map.ContainsKey(lst.Property))
{
map.Add(item.Property, 1);
}
else
map[item.Property]++;
}
var z = lst.Select(l => new GetRfqResponse{
Id = l.ID,
Count = map[l.Property]
});

Related

Sorting by nested Dictionary value?

var userInformation = new Dictionary<string, Dictionary<string, int>>();
I need a new dictionary that equals this one, but is sorted first by key then by the value's value. I tried:
var resultInformation = userInformation.OrderBy(k => k.Key).ThenBy(v => v.Value.OrderByDescending(x => x.Value));
I tried a couple of other methods but no effect.
Dictionaries aren't sorted, but you can easily produce a list/collection of the items in your dictionaries, like so:
var resultInformation = from outer in userInformation
from inner in outer.Value
let data = new { Outer = outer.Key, Inner = inner.Key, Value = inner.Value }
orderby data.Outer, data.Inner, data.Value
select data;
Or the query syntax equivalent:
var resultInformation = userInformation
.SelectMany(i => i.Value, (key, inner) => new { Outer = key, Inner = inner.Key, Value = inner.Value})
.OrderBy(e => e.Outer)
.ThenBy(e => e.Inner)
.ThenBy(e => e.Value);
Update: Based on your clarifying comment, I think what you really want is something more like this:
var resultInformation =
from student in userInformation
orderby student.Key
select new
{
studentId = student.Key,
courses =
from courseScore in student.Value
orderby courseScore.Value descending
select new {
course = courseScore.Key,
score = courseScore.Value
}
};

foreach to linq expression help needed

having some trouble writing the following code to some nicer/less lines :)
any one have the good solution?
//custom implementation for popular filters
var popularFilter = new Dictionary<string, int>();
foreach (var car in allFilteredCars)
{
foreach (var offering in car.Offerings)
{
if (popularFilter.ContainsKey(offering))
popularFilter[offering] = popularFilter[offering] + 1;
else
popularFilter.Add(offering, 1);
}
}
categories.Add(new Category
{
Name = "popular",
Code = "popular",
Values = popularFilter.Select(p => new Value
{
Code = p.Key,
Name = p.Key,
Count = p.Value
}).ToList()
});
If it is possible i want i directly to add it in the categories list.
car.offerings = list<string>
so basicly something like:
Categories.Add(allFilteredCars.SelectMany(
c => c.Offerings.Select(
o => new {
something magical here}
.Select(a =>
new Category{
code.. etc etc..}
));
It looks like you just want to do a SelectMany to get the offerings, then group them and select the Count.
categories.Add(new Category
{
Name = "popular",
Code = "popular",
Values = allFilteredCars.SelectMany(c => c.Offerings)
.GroupBy(o => o)
.Select(grp => new Value
{
Code = grp.Key,
Name = grp.Key,
Count = grp.Count()
}).ToList()
});
Your non linq code already looks quite fine.
You can create your dictionary with linq by using a GroupBy & ToDictionary:
var dictionary = offerings
.GroupBy(x => x)
.ToDictionary(x => x.Key, x => x.Count());

Getting count of values in dictionary using LINQ

I am having a dictionary type <int, list<int>>. I am trying to count number of value instances repeated for that particular key.
I tried
LINQquery = dict.SelectMany(keyvalues => keyvalues.Value.GroupBy(values => values).Select(values => new {key = keyvalues.Key, value = values.Key, count = values.Count(),votescasted = keyvalues.Value.Count}));
resultList = LINQquery.ToList();
By this LINQ I am creating a new list entry for every unique value in my dictionary. I am ending up with multiple key entries in my list. How can I modify my query so that I will have a result list having key,countvalue1,countofvalue2..,countofvalueN ?
my input is dict{500,{25,26,25,25}}
with my LINQ I am getting a list
key=500,value=25,count=3
key=500,value=26,count=1
how can I modify my query so that my output list can be
key=500,countof25=3,countof26=1.
I believe this will do what you want:
var x = dict
.Select(d => new { Key = d.Key,
Counts = d.Value.GroupBy(v => v)
.Select(g =>
new { Value = g.Key,
Count = g.Count() })});
then we can add:
x.Select(i => $"Key = {i.Key}, " +
String.Join(", ", i.Counts.Select(c => $"countof{c.Value}={c.Count}" ))).Dump();
and we get :
Key = 500, countof25=3, countof26=1

How to filter a list based on 2 properties?

I have a list in my code that I need to filter through and return specific rows based on two criteria. The List in question is a list of models from a database. There are two ID properties on each model, one is the ID from the data table and is unique, the other is an ID we use to identify groups and can repeat. We'll call them ID and GroupID. Basically, I want the resulting list to have only one of each GroupID, and it should be the one with the highest (numerically speaking) ID. For example:
Input:
List<MyModel> modelList = new List<MyModel>
modelList[0].ID = 1 modelList[0].GroupID = 5
modelList[1].ID = 2 modelList[1].GroupID = 5
modelList[2].ID = 3 modelList[2].GroupID = 6
modelList[3].ID = 4 modelList[3].GroupID = 6
Desired Output:
Models at indexes 1 and 3.
Using LINQ:
var items = (from model in modelList
group model by model.GroupID into modelGroup
select modelGroup.Max(i => i.ID)).ToList();
What you have to do here is first order the modelList by ID and then GroupBy the list items by GroupID, then pull the item with max Id value.
var result = modelList.OrderByDescending(x => x.ID).GroupBy(x => x.GroupID).Select(x => x.First());
the above query will give you the result.
This is your solution:
var myData = models.GroupBy(model => model.GroupId)
.Select(group => group.OrderByDescending(model => model.Id).First());
Or you could also do this:
var myData = models.GroupBy(model => model.GroupId)
.Select(group => group.First(model => model.Id == group.Max(model1 => model1.Id)));
For fun, here's a fiddle.
You can try to use GroupBy.
var q = modelList.GroupBy(x => x.GroupID, x => x,
(key, g) => new {
GroupID = key,
Id = g.Max(c => c.ID)
});
This should group all your elements by GroupId and select Max ID in one of that groups.
Try this code:
List<MyModel> modelList = new List<MyModel>();
modelList.Add(new MyModel());
modelList.Add(new MyModel());
modelList.Add(new MyModel());
modelList.Add(new MyModel());
modelList[0].ID = 1; modelList[0].GroupID = 5;
modelList[1].ID = 2; modelList[1].GroupID = 5;
modelList[2].ID = 3; modelList[2].GroupID = 6;
modelList[3].ID = 4; modelList[3].GroupID = 6;
var list = from ml in modelList group ml by ml.ID into r select new { ID = r.Key, MaxGroupID = r.Max() };
this might help you
modelList.GroupBy(model => model.GroupId, g => g.Id).Select(item => item.Max())
var newModelList = modelList.GroupBy(ml => ml.GroupID)
.Select(g => new MyModel
{
ID = g.OrderByDescending(x => x.ID).First().ID,
GroupID = g.Key
}).ToList();
Details
1) GroupBy then Select to get distinct items over GroupID.
2) First() after OrderByDescending to get highest ID.
3) new MyModel in Select is just to be explicit about the projection.

Search an Object list for duplicate keys, and place string values into a string array

What I want to be able to do is search the searchValues list for duplicate itemId's, and when I find them, place the single string value into the string values array.
The SearchValue object:
public class SearchValue<TItemId>
{
public TItemId ItemId { get; set; }
public string Value { get; set; }
public string[] Values { get; set; }
}
My test search values after init looks like this:
searchValues[0]
.ItemId == 16
.Value == "2"
searchValues[1]
.ItemId == 16
.Value == "3"
searchValues[2]
.ItemId == 15
.Value == "6"
searchValues[3]
.ItemId == 15
.Value == "3"
searchValues[4]
.ItemId == 5
.Value == "Vertonghen"
I'd like my final result to look like this:
searchValues[0]
.ItemId == 16
.Values == "2,3"
searchValues[1]
.ItemId == 15
.Values == "6,3"
searchValues[2]
.ItemId == 5
.Value == "Vertonghen"
I'd really want to do this using LINQ. I've managed to create another List of SearchValue thusly:
List<SearchValue<Byte>> duplicateSearchItems = (from x in searchValues
group x by x.ItemId into grps
orderby grps.Key
where grps.Count() > 1
select grps).SelectMany(group => group).ToList();
...but getting the value into the values array is giving me trouble. Ideally if the LINQ could return a single list that contains the duplicate records transmogrified into the array with the non-duplicates intact would be best. Probably a nested query of some sort? I'm stumped. Any ideas?
Thanks in advance!
why don't you use Dictionary
Dictionary<int,string> d = new Dictionary<int,string>();
foreach(var x in searchValues)
{
if(d.ContainsKey(x.ItemId))
d[x.ItemId] = string.Format("{0},{1}",d[x.ItemId],x.Value);
else
d.Add(x.ItemId,x.Value);
}
on the end simply iterate throug the Dictionary
foreach(var entry in d)
{
ConsoleWriteline(entry.Key+" : "+entry.Value);
}
Linq alone cannot be used to modify the original list or to modify the items in the list. However, you could do this to create a new list:
List<SearchValue<Byte>> results =
(from x in searchValues
group x by x.ItemId into g
select new SearchValue<Byte>()
{
ItemId = g.Key,
Value = g.Value.First().Value,
Values = g.Value.Select(i => i.Value).ToArray(),
}
.ToList();
Or in fluent syntax:
List<SearchValue<Byte>> results = searchValues
.GroupBy(x => x.ItemId)
.Select(g => new SearchValue<Byte>()
{
ItemId = g.Key,
Value = g.Value.First().Value,
Values = g.Value.Select(i => i.Value).ToArray(),
})
.ToList();
However, depending on your situation, an ILookup may be more appropriate for you:
var results = searchValues.ToLookup(x => x.ItemId, x => x.Value);
Console.Write(String.Join(", ", results[16])); // 2, 16
I don't think LINQ would provide you with the best solution here. Similar to Nikola, I'd use a Dictionary. If you aren't married to your SearchValue data type, you can avoid the second loop that just pushes your data back into your type. A Dictionary> would work here.
var searchValues = new List<SearchValue<int>>();
var distinctItemIds = new Dictionary<int, List<string>>();
foreach (var item in searchValues)
{
if (!distinctItemIds.ContainsKey(item.ItemId))
{
distinctItemIds.Add(item.ItemId, new List<string>());
}
// Add the value
distinctItemIds[item.ItemId].Add(item.Value);
}
// Put values back into your data object
var finishedValues = new List<SearchValue<int>>();
foreach (var keyValuePair in distinctItemIds)
{
finishedValues.Add(new SearchValue<int>()
{
ItemId = keyValuePair.Key,
Values = keyValuePair.Value.ToArray()
});
}
I managed to work it out using LINQ.
// Get a new list of unique items to add our duplicated items to
List<SearchValue<Byte>> finalSearchItems = (from x in searchValues
group x by x.ItemId into grps
orderby grps.Key
where grps.Count() == 1
select grps).SelectMany(group => group).ToList();
byte[] duplicateIds = (from x in searchValues
group x by x.ItemId into grps
where grps.Count() > 1
select grps.Key).ToArray();
// Smash the string 'Value' into 'Values[]'
foreach (byte id in duplicateIds)
{
SearchValue<Byte> val = new SearchValue<byte>();
val.ItemId = id;
// Smash
val.Values = (from s in searchValues
where s.ItemId == id
select s.Value).ToArray();
finalSearchItems.Add(val);
}

Categories

Resources