Get Max occurence of element in Linq - c#

Hello all i have 2 class for the example i will name it A and B
A is a list and every A element have a list of B element.
B element have a type
I want to get a B element by occurance of it in my list of B element.
var listB = A
.SelectMany(a => a.B);
var listBId = listB
.Where(b => b.Type == SelectedType)
.Select(b => b.Id);
var IdMaxoccur = listBId
.GroupBy(x => x)
.OrderByDescending(x => x.Count())
.First()
.Key;
I find this a bit heavy for just get the max occurence of an id in a list....
Do you know a better way to do this?

I think your code is good enough if you rewrite and simplify it a bit and handle case when your list is empty. This code assumes that 0 is not a valid Id.
var result = A
.SelectMany(x => x.B)
.Where(x => x.Type == selectedType)
.GroupBy(x => x.Id, new { Id = x.Key, Count = x.Count() })
.OrderByDescending(x => x.Count)
.FirstOrDefault();
Console.WriteLine("Max ID = {0}, Count = {1}", result.Id, result.Count);
If you still think that your existing code is too complex, you could write extension method to hide complexity
public static int TryGetBIdWithMaxOccur(this IEnumerable<A> input, SelectedTypeEnum selectedType)
{
var result = input
.SelectMany(x => x.B)
.Where(x => x.Type == selectedType)
.GroupBy(x => x.Id, new { Id = x.Key, Count = x.Count() })
.OrderByDescending(x => x.Count)
.Select(x => x.Id)
.FirstOrDefault();
return result;
}
Then you can use it like this:
var result = A.TryGetBIdWithMaxOccur(SelectedTypeEnum.CoolValue);
if(result != default(int))
{
//do stuff
}

just an idea
var bs = A.SelectMany().Where().Select(b=>b.Id).OrderBy();
int current = -1, maxB = -1; // make sure it is stub Id
int currentCount = 0, maxCount = 0;
foreach(var b in bs)
{
if (b != current)
{
// check if previous was max
if (currentCount > maxCount)
{
maxB = current;
maxCount = currentCount;
}
// change current
current = b;
currentCount = 0;
}
currentCount ++;
}

To make it a bit shorter you can put the Where selector inside SelectMany and use GroupBy overload:
var idMaxOccur = A
.SelectMany(a => a.B.Where(b => b.Type == selectedType))
.GroupBy(b => b.Id, b => b.Id)
.OrderByDescending(g => g.Count())
.First().Key;

Related

C#:How to get the longest common prefix from a list of strings LINQ expression

I am trying to learn LINQ
I would like to understand how to get the longest common prefix from a list of strings
{"a","abC","abcD"}
would return "ab". Common as in at least 1 other string has it. Even though "a" is common for all 3, I would like to get "ab" because 2 elements share this prefix and "ab" is longer than "a"
It was an interesting challenge and this is my solution:
var array = new []{"a","abC","abcD"};
var longestCommonPrefix = Enumerable.Range(1, array.Max(_ => _)!.Length)
.Select(i =>
{
var grouped = array.Where(x => x.Length >= i)
.GroupBy(x => x[..i])
.Where(x => x.Count() > 1)
.OrderByDescending(x => x.Count())
.Select(x => new { LongestCommonPrefix = x.Key })
.FirstOrDefault();
return grouped?.LongestCommonPrefix ?? string.Empty;
}).Max();
var longestCommonPrefix = (words.FirstOrDefault() ?? String.Empty)
.Substring(0,
Enumerable.Range(0, words.Any() ? words.Min(x => x.Length) + 1 : 0)
.Where(x => words.Select(w => w.Substring(0, x))
.Distinct().Count() == 1).DefaultIfEmpty(0).Max()
);

C# Linq Lambda for group by multiple columns select max

I want to translate this into lambda syntax and can't seem to get it to work:
Grouping by two columns, select max on a different column, return list of complete complex object.
I am writing more text here to get past the validation on this form. How much text is needed until I am allowed to post this?
_clientpolicies = (from policy in
_reply.CommercialInsuredGroupWithPolicyTerm.InsuredWithPolicyTerm.SelectMany(x => x.PolicyTerm)
.Where(x => !(string.IsNullOrWhiteSpace(x.PolicyNumber) && string.IsNullOrWhiteSpace(x.ControlNumber)))
.Where(x => x.Insured.DNBAccountNumber == _client.LookupID)
group policy by
new
{
PolicyReference = GetPolicyReference(policy),
PolicyType = policy.ProductInformation.PolicyTypeCode
}
into g
let maxPolicyInception = g.Max(p => p.InceptionDate)
from policyGroup in g
where policyGroup.InceptionDate == maxPolicyInception
select policyGroup).ToList();
I dont think there's a way of doing it in one line. So there's my try :
policyGroups=
_reply.CommercialInsuredGroupWithPolicyTerm.InsuredWithPolicyTerm
.SelectMany(x => x.PolicyTerm)
.Where(x => !(string.IsNullOrWhiteSpace(x.PolicyNumber) && string.IsNullOrWhiteSpace(x.ControlNumber)))
.Where(x => x.Insured.DNBAccountNumber == _client.LookupID)
.GroupBy(x => GetPolicyReference(x))
.ThenBy(x => x.ProductInformation.PolicyTypeCode)
.ToList();
var maxPolicyInception = policyGroups.Max(p => p.InceptionDate);
_clientpolicies = policyGroups
.Where(g => g.InceptionDate == maxPolicyInception)
.ToList();
_clientpolicies =
_reply.CommercialInsuredGroupWithPolicyTerm.InsuredWithPolicyTerm.SelectMany(x => x.PolicyTerm)
.Where(x => !(string.IsNullOrWhiteSpace(x.PolicyNumber) && string.IsNullOrWhiteSpace(x.ControlNumber)))
.Where(x => x.Insured.DNBAccountNumber == _client.LookupID)
.GroupBy(x =>
new
{
PolicyReference = GetPolicyReference(x),
PolicyType = x.ProductInformation.PolicyTypeCode
},
(key, g) => g.OrderByDescending(gx => gx.InceptionDate).First()

LINQ - Select min count

I have a list of strings which contain X in them. I want to select list(s) with the minimum count of X in them. For example:
CountMin("AXBXX", "AAX") will return AAX.
How can I write this qith LINQ in a concise way ?
public static string CountMin(IList<string> inputList)
{
if (inputList == null || !inputList.Any()) return null;
var result = inputList.Select(s => new
{
Item = s,
Count => s.Count(ch => ch == 'X')
})
.OrderBy(item => item.Count).First().Item;
}
Snippet assumes that all elements on list are different to null. If you need it, it could be easily improved.
You can also omit temporary class:
inputList.OrderBy(s => s.Count(c => c == 'X')).First();
string[] list = {"AXBXX", "AAX", "AXX"};
string result = (from word in list
select new { word, wordLen = (word.Length - (word.Replace("X", "")).Length) })
.OrderBy(x => x.wordLen).First().word;
MessageBox.Show(result);
Here's an answer that will get you all of the minimum X strings from the list.
var listOfStrings = new List<string>()
{
"AXB",
"ABXXC",
"ABX",
};
var minimumXs =
listOfStrings
.GroupBy(x => x.Count(y => y == 'X'))
.OrderBy(x => x.Key)
.Take(1)
.SelectMany(x => x);
That gives me:
AXB
ABX

Avoid Repeating Group by Linq in C#

I need to optimize My Code. I Have Some Repeating Code. But I would like to optimize it. Can any one please help me to optimize My Code. How Can I greate Common Function For this???
foreach (var item in hotellocation.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count()))
{
if (item.Key != "")
{
lstHotelLocation.Add(new HotelLocation()
{
Name = item.Key,
count = item.Value
});
}
}
//need to Apply to linq
foreach (var item in hoteltype.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count()))
{
if (item.Key != "")
{
lstHotelType.Add(new HotelTypeFilter()
{
Name = item.Key,
count = item.Value
});
}
}
The first thing to do is get rid of those foreach loops, as they are incongruous with LINQ, and ditch the dictionary, since it's pointless:
var lstHotelLocation = hotellocation.GroupBy(x => x)
.Where(g => g.Key != "")
.Select(g => new HotelLocation {
Name = kv.Key,
count = g.Count()
})
.ToList();
var lstHotelType = hoteltype.GroupBy(x => x)
.Where(g => g.Key != "")
.Select(g => new HotelTypeFilter {
Name = g.Key,
count = g.Count()
})
.ToList();
If you want to further remove the duplication, you can do this:
static List<T> AssembleCounts<T>(IEnumerable<string> values,
Func<string, int, T> makeObject)
{
return values.Where(x => !string.IsNullOrEmpty(x))
.GroupBy(x => x)
.Select(g => makeObject(g.Key, g.Count()))
.ToList();
}
var lstHotelLocation = AssembleCounts(hotellocation,
(k, c) => new HotelLocation {
Name = k, count = c
});
var lstHotelType = AssembleCounts(hoteltype,
(k, c) => new HotelTypeFilter {
Name = k, count = c
});

Get index of lines that match my linq

I have a linq statement and I would like to know if it is possible to get indicies of lines that match my statement? Here it is:
var result = list3.Where(middle => list4.Any(x => x == middle.Middle.category1)).Select(obj => new { obj, dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= datetimepickerChoice1 && x.dt <= datetimepickerChoice2)
.Select(x => x.obj).ToList();
You can use the overload of Select (or Where) which projects also the index of the element:
var result = list3.Select((middle, index) => new{ middle, index })
.Where(x => list4.Any(xx => xx == x.middle.Middle.category1))
.Select(x => new { x.middle, x.index, dt = DateTime.ParseExact(x.middle.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= czas11 && x.dt <= czas22)
.Select(x => x.index)
.ToList();
Side-note: consider to change your variable names to be more meaningful. That is unreadable.
do you mean this?
var result = list3.Where(middle => list4.Any(x => x == middle.Middle.category1))
.Select(obj => new { obj, dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= czas11 && x.dt <= czas22)
.Select((x,index) =>new{ x.obj,Index=index}).ToList();
Also note that if you want to search for the indicies of items matching a predicate very often, it could be worth writing a very simple extension method:
public static class IEnumerableExt
{
public static IEnumerable<int> FindIndices<T>(this IEnumerable<T> self, Predicate<T> predicate)
{
int i = 0;
foreach (var element in self)
{
if (predicate(element))
yield return i;
++i;
}
}
}
Which you would call like this:
var result = list3.FindIndices(x => list4.Any(xx => xx == x.middle.Middle.category1));

Categories

Resources