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));
Related
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;
This works fine.g.Key is not null and has appropriate data:
var result = db.JournalEntries.Include(je => je.JournalRecords.Select(jr => jr.Account).Select(j => j.AccountParticulars))
.Where(je => je.Date >= existingLedgerTransaction.From && je.Date <= existingLedgerTransaction.To)
.SelectMany(s => s.JournalRecords)
.GroupBy(d => d.AccountParticular.Account.AccountCategory)
.Select(g => new { Name = g.Key.Name });
But this does not work as g.Key is null:
var DateFilter = new Func<JournalEntry, bool>(je => je.Date >= existingLedgerTransaction.From && je.Date <= existingLedgerTransaction.To);
var result = db.JournalEntries.Include(je => je.JournalRecords.Select(jr => jr.Account).Select(j => j.AccountParticulars))
.Where(DateFilter)
.SelectMany(s => s.JournalRecords)
.GroupBy(d => d.AccountParticular.Account.AccountCategory)
.Select(g => new { Name = g.Key.Name });
I tried the same thing in a simple console app with static collection and passing in predicate works fine. What could be the problem here?
NOTE: Lazy loading/dynamic proxy is disabled
Try
var DateFilter = new Expression<Func<JournalEntry, bool>>(je => je.Date >= existingLedgerTransaction.From && je.Date <= existingLedgerTransaction.To);
as you need to pass an expression tree to EF
Hello is there a way to dynamically cast inside the following code so I do not need a bunch of if statements with nearly identical code?
List<DateTime> dateTimeList = null;
if(_dataSeriesList[0].GetType().Name == "Class1")
{
dateTimeList =
_dataSeriesList.ConvertAll(x => (Class1) x)
.Where(d => d.Time >= min && d.Time <= max)
.OrderBy(t => t.Time)
.Select(d => d.Time)
.ToList();
}
else if(_dataSeriesList[0].GetType().Name == "Class2")
{
dateTimeList =
_dataSeriesList.ConvertAll(x => (Class2) x)
.Where(d => d.Time >= min && d.Time <= max)
.OrderBy(t => t.Time)
.Select(d => d.Time)
.ToList();
}
.
.
and so on
I tried using the following code:
public static T Cast<T>(object o)
{
return (T)o;
}
Type t2 = _dataSeriesList[0].GetType();
dateTimeList =
_dataSeriesList.ConvertAll(x => castMethod.Invoke(null, new object[] { x }))
.Where(d => d.Time >= min && d.Time <= max)
.OrderBy(t => t.Time)
.Select(d => d.Time)
.ToList();
But then the linq statement will not compile.
If they don't share a common base type you can do it like this:
dateTimeList =
_dataSeriesList.Select(x => {
if (x.GetType().Name == "Class1")
return ((Class1)x).Time;
else
return ((Class2)x).Time;
})
.Where(d => d >= min && d <= max)
.OrderBy(t => t)
.Select(d => d)
.ToList();
Since all you are doing is working with the time element you just select out the item of interest according to your rules and then use it in a common way.
Of course if what you are working with is more complicated you select that information instead.
This is fairly standard in Linq -- make a new type on the fly that you need in order to do your work.
((as has been pointed out in the comments "on the fly" is actually determined at compile time and not dynamic in the typical use of the word))
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
Say I have an array like this
string [] fruits = {"watermelon","apple","apple","kiwi","pear","banana"};
Is there an built in function that allows me to query all the index of "apple" ?
For example,
fruits.FindAllIndex("apple");
will return an array of 1 and 2
If there is not, how should I implement it?
Thanks!
LINQ version:
var indexes = fruits.Select((value, index) => new { value, index })
.Where(x => x.value == "apple")
.Select(x => x.index)
.ToList();
Non-LINQ version, using Array<T>.IndexOf() static method:
var indexes = new List<int>();
var lastIndex = 0;
while ((lastIndex = Array.IndexOf(fruits, "apple", lastIndex)) != -1)
{
indexes.Add(lastIndex);
lastIndex++;
}
One way would be to write like this:
var indices = fruits
.Select ((f, i) => new {f, i})
.Where (x => x.f == "apple")
.Select (x => x.i);
Or the traditional way:
var indices = new List<int>();
for (int i = 0; i < fruits.Length; i++)
if(fruits[i] == "apple")
indices.Add(i);
Pretty easy with an extension method.
var fruits = new[] { "watermelon","apple","apple","kiwi","pear","banana" };
var indexes = fruits.FindAllIndexes("apple");
public static class Extensions
{
public static int[] FindAllIndexes(this string[] array, string search) => array
.Select((x, i) => (x, i))
.Where(value => value.x == search)
.Select(value => value.i)
.ToArray();
}