i have a collection of elements sorted by the elements' Name property. i need to insert a new element into the collection while maintaining the order. i am looking for a concise LINQ way to do this. my code is below. "this.Children" is the collection, and "d" is the new element that i need to insert. it takes two passes over the collection to find the insertion point. is there a way to get the index from the First() extension method? (please do not suggest using foreach, i know that :), i am learning LINQ).
thanks!
konstantin
var v = this.Children.FirstOrDefault(x => string.Compare(x.Name, d.Name) > 0);
int index = this.Children.IndexOf(v);
if (index < 0)
{
this.children.Add(d);
}
else
{
this.Children.Insert(index, d);
}
Yes, using the overload of Select which includes the index as well as the value:
var pair = this.Children
.Select((value, index) => new { value, index })
.FirstOrDefault(x => string.Compare(x.value.Name, d.Name) > 0);
if (pair == null)
{
Children.Add(d);
}
else
{
Children.Insert(pair.index, d);
}
Note that this is still inefficient though - if you already know the values are sorted, you can use a binary chop to find out the insertion index. It's hard to give sample code for that without knowing the type of Children though... there's already List<T>.BinarySearch and Array.BinarySearch.
Learning LINQ is admirable - but it's also important to learn when using LINQ isn't the best way to go :)
Assuming that this.Children is a List<T>, you can use List<T>.BinarySearch with a custom comparer to efficiently find the position to insert the new element at:
IComparer<Foo> comparer = AnonymousComparer.Create<Foo>(
(x, y) => string.Compare(x.Name, y.Name));
int index = this.Children.BinarySearch(d, comparer);
if (index < 0) index = ~index;
this.Children.Insert(index, d);
with
static class AnonymousComparer
{
public static IComparer<T> Create<T>(Func<T, T, int> comparer)
{
if (comparer == null) { throw new ArgumentNullException("comparer"); }
return new TheComparer<T>(comparer);
}
private class TheComparer<T> : IComparer<T>
{
private readonly Func<T, T, int> c;
public TheComparer(Func<T, T, int> c) { this.c = c; }
int IComparer<T>.Compare(T x, T y) { return this.c(x, y); }
}
}
I created my own Extension method for adding a new item in the correct order:
public static class ListExtension
{
public static void InsertOrderedBy<TSource, TKey>(this IList<TSource> source, TSource item, Func<TSource, TKey> keySelector) where TKey : IComparable<TKey>
{
var i = source.Select((Value, Index) => new { Value, Index }).FirstOrDefault(x => keySelector(x.Value).CompareTo(keySelector(item)) > 0);
if (i == null)
{
source.Add(item);
}
else
{
source.Insert(i.Index, item);
}
}
}
I use it like this:
List<Item> ItemList = new List<Item>();
ItemList.InsertOrderedBy(item, x => x.Duration);
It's almost the same like the answer from Jon Skeet, but I can pass the sort argument as second parameter, e.g. a Duration (type TimeSpan).
Well, you could always just use OrderBy after adding the new element...
var v = this.Children.Union(new List<TypeOfChildren>() { d }).OrderBy<TypeOfChildren, string>(x => x.Name).ToList<TypeOfChildren>();
Related
I have always read that overloaded methods should always return the same type whenever possible.
However I've come upon a scenario which I really don't know if it could be considered as having different return types or not.
Consider the following implementation to obtain the permutations of all elements of a given collection taken k at a time where the elements the make up the permutation are aggregated to the consumer's needs.
public static IEnumerable<Q> GetPermutations<T, Q>(this IEnumerable<T> collection, int k, Func<IEnumerable<T>, Q> aggregator)
{
if (k <= 0)
return Enumerable.Empty<Q>();
return collection.getPermutations(k).Select(p => aggregator(p));
}
private static IEnumerable<IEnumerable<T>> getPermutations<T>(this IEnumerable<T> set, int k) =>
k == 0 ? new[] { Enumerable.Empty<T>() }
: set.SelectMany((item, index) => set.SkipAt(index).getPermutations(k - 1).Select(p => new[] { item }.Concat(p)));
private static IEnumerable<T> SkipAt<T>(this IEnumerable<T> collection, int index)
{
var counter = 0;
foreach (var item in collection)
{
if (counter != index)
{
yield return item;
}
counter++;
}
}
Now I want to define an overload that takes no aggregator and simply returns each permutation as an IEnumerable<T>.
My first implementation looked as follows:
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<T> collection, int k)
=> GetPermutations(collection, k, p => p);
Pretty straightforward. But then I realized that I am in someway changing the return type of the method. If inspected in intellisense, the first returns IEnumerable<Q> while the second returns IEnumerable<IEnumerable<T>> and the type parameter Q dissapears.
Should this be any cause of concern? Can it create confussion and should be avoided if possible? Technically the return type does not change, as IEnumerable<IEnumerable<T>> is an IEnumerable<Q> but it still caught my eye when reviewing the code as I don't recall seeing anything similar before.
The workaround I immediately thought of was to make aggregator optional, but this runs into its own problems:
public static IEnumerable<Q> GetPermutations<T, Q>(this IEnumerable<T> collection, int k, Func<IEnumerable<T>, Q> aggregator = null)
{
if (k <= 0)
return Enumerable.Empty<Q>();
var myAggregator = aggregator ?? new Func<IEnumerable<T>, Q)(p => p); //Compile time error, no implicit conversion from `IEnumerable<T>` to `Q`
return collection.getPermutations(k).SelectMany(p => new[] { myAggregator(p) });
}
Note that the second type parameter Q is necessary due to our needs and the corner case provided by string being an IEnumerable<char>. An aggregator of type Func<IEnumerable<T>, T> for instance would not work:
var str = "1234";
var permutations = str.GetPermutations(4, p => Concat(p)); // compile time error, `string` is not a `char`.
Is the proposed overload acceptable or is there a workaround I am not considering available to make the optional argument solution work?
I'm writing an entry for an AI competition in C#, and I'm looking for a more elegant way to search for items. (I'm much more familiar with embedded C programming, but I prefer C# for an AI contest.)
The contest server is using dmcs to compile entries, which is .Net framework 4.0; I'm using Visual Studio Express 2013 for my testing.
I'm trying to search for an item in a list with the maximum value of a parameter that also meets a certain prerequisite. I don't want the maximum value, though, I want the item that has said maximum value.
Here's my original code that does what I want using a foreach loop:
List<Region> myList = new List<Region>();
// ...
// myList gets populated with elements
// ...
Region biggest = null;
int biggestSize = -1;
foreach (Region r in myList)
{
// We only want elements that are eligible for expansion
if (r.EligibleForExpansion())
{
if (r.Size > biggestSize)
{
biggest = r;
biggestSize = r.Size;
}
}
}
return biggest; // I want the biggest Region, not the Size of the biggest region.
I'm trying to find a more elegant way to do this so I don't have foreach loops all over my code. I tried this:
return myList.Max(delegate(Region r) { if (r.EligibleForExpansion()) return r.Size; else return -1; });
However, that returns the Size value of the largest region, not the largest Region itself (which is what I need).
I know that my foreach code will return null if no Region meets the requirement while the Max code will give -1 (or any Region that doesn't meet the requirement); I can deal with either way.
I don't think I can just make Region IComparable, though; I have many searches for Region objects, and I need to sort by different parameters at different times, so the comparison function would be different in different searches.
I could just wrap my foreach code in a static function and call that wherever I need to search, but it seems like there should be a more elegant way to do this in C#.
Use MaxBy from moreLINQ library:
public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> selector)
{
return source.MaxBy(selector, Comparer<TKey>.Default);
}
public static TSource MaxBy<TSource, TKey>(this IEnumerable<TSource> source,
Func<TSource, TKey> selector, IComparer<TKey> comparer)
{
if (source == null) throw new ArgumentNullException("source");
if (selector == null) throw new ArgumentNullException("selector");
if (comparer == null) throw new ArgumentNullException("comparer");
using (var sourceIterator = source.GetEnumerator())
{
if (!sourceIterator.MoveNext())
{
throw new InvalidOperationException("Sequence contains no elements");
}
var max = sourceIterator.Current;
var maxKey = selector(max);
while (sourceIterator.MoveNext())
{
var candidate = sourceIterator.Current;
var candidateProjected = selector(candidate);
if (comparer.Compare(candidateProjected, maxKey) > 0)
{
max = candidate;
maxKey = candidateProjected;
}
}
return max;
}
}
like that:
var item = myList.Where(x => x.EligibleForExpansion())
.MaxBy(x => x.Size);
How about this?
myList.Where(r => r.EligibleForExpansion).OrderBy(r => r.Size).LastOrDefault()
You can use Aggregate out of the box for this purpose:
var item = myList
.Where(r => r.EligibleForExpansion())
.Aggregate((Region)null, (max, cur) => (max == null ? cur : cur.Size > max.Size ? cur : max));
If Region were a value type (which it isn't) you could wrap the initial value in a nullable, and get a null value for an empty list:
var item = myList
.Where(r => r.EligibleForExpansion())
.Aggregate((Region?)null, (max, cur) => (max == null ? cur : cur.Size > max.Value.Size ? cur : max));
I have the following code
List<int> GetIndices<T>(List<T> list, ?????? condition
{
var result =
list
.Select((p, index) => index)
.Where(condition);
return result.ToList();
}
And I would like to call it like GetIndices(someList, (p, index) => (someList[index].Height < someList[index - 1].Height))
What is the correct type of condition?
There's an error in your code: Where expects a delegate that returns a bool value and has the list element type as input.
var result = list
.Select((p, index) => index) // projects the element to it's index (of type int)
.Where(condition); // => expects Func<int, bool>
So you would need Func<int,bool>
However, from your spec I think you want Func<T,int,bool>, which means you have to rewrite your implementation of GetIndices as
var result = list
.Select((p, index) => new {p, index})
.Where(x => condition(x.p, x.index))
.Select(x => x.index);
Func<T, bool>
Should do the trick but you're going to have to modify your lambda a bit because you can't pass the index (if you want to use condition in the Where clause). You could easily change your lambda to:
p => someList[someList.IndexOf(p).Height < someList[someList.IndexOf(p)-1].Height
For future reference, the MSDN documentation for the extension methods is great once you learn how to read it (that part takes a bit):
MSDN - Enumerable.Where Method
Since this is an extension method, the first parameter (IEnumerable<TSource>) is the collection you're calling the method on (List<T> in your case).
The second parameter is what you need to match. Since the documentation calls for Func<TSource, bool> and TSource is T in your case...you get Func<T, bool>
Like jeroenh realized, you need to capture the original index. The Funct<T,int,bool> condition you pass only needs to be aware of the item and its index, not the anonymous type created in the query, so the condition passed changes a bit. It also should handle the situation where the index == 0 and therefore there are no preceding items (index - 1).
class Program {
static void Main( string[] args ) {
var items = Item.GetItems();
// mind the case where index == 0 so you don't grab an item out of bounds
var ind = GetIndices( items,
( p, index ) => ( h.index == 0 ) ? false : p.Height < items[ index - 1 ].Height );
}
static List<int> GetIndices<T>( List<T> list, Func<T, int, bool> condition ) {
var res = list
.Select( ( item, index ) => new { item, index } ) // capture original index
.Where( h => condition( h.item, h.index ) )
.Select( h => h.index ); // reduce to the index again
return res.ToList();
}
}
class Item {
public int Height {
get;
set;
}
public Item( int h ) {
Height = h;
}
static public List<Item> GetItems() {
return new List<Item>( new[]{
new Item(1),
new Item(4),
new Item(2),
new Item(5)
} );
}
}
Try Func<bool>.
Or rather a variant with the correct amount of input parameters.
I need to get a Kvp from a list of List<KeyValuePair<Int, Int>> depending on the minimum value.
I have tried this:
KeyValuePair<Int, Int> kvp= listOfKvps.Min(e=> e.Key);
but this return only the value, not the whole KeyValuePair which I need.
var min = listOfKvps.OrderBy(kvp => kvp.Key).First();
If you want to do it with a single O(n) pass through the sequence, rather than requiring an O(n log n) ordering, then you could do it like this:
var min = listOfKvps.Aggregate((agg, kvp) => (kvp.Key < agg.Key) ? kvp : agg);
(Of course, the second version is much less readable/intuitive than the first, even if it does have better theoretical performance. It would make more sense to use some sort of MinBy method: either write your own, use the version from Marc's answer or use the version from MoreLINQ.)
There is no inbuilt MinBy method, so you could either write a MinBy extension method, or just .OrderBy(x => x.Key).First(). A MinBy would be O(n) so would be more efficient - but more code to write ;p
For example, you could use:
var kvp= listOfKvps.MinBy(e=> e.Key);
with:
public static class SomeUtil {
public static TSource MinBy<TSource, TValue>(
this IEnumerable<TSource> source, Func<TSource, TValue> selector) {
using (var iter = source.GetEnumerator())
{
if (!iter.MoveNext()) throw new InvalidOperationException("no data");
var comparer = Comparer<TValue>.Default;
var minItem = iter.Current;
var minValue = selector(minItem);
while (iter.MoveNext())
{
var item = iter.Current;
var value = selector(item);
if (comparer.Compare(minValue, value) > 0)
{
minItem = item;
minValue = value;
}
}
return minItem;
}
}
}
I would suggest you use the MinBy extension-method from MoreLinq.
Alternatively:
var minKey = listOfKvps.Min(kvp => kvp.Key);
var minKvp = listOfKvps.First(kvp => kvp.Key == minKey);
This is still O(n), although it requires 2 passes over the list. Sorting the list and then picking the first element is more terse, but is O(n * logn), which may be relevant for larger lists.
This question already has answers here:
Split List into Sublists with LINQ
(34 answers)
Closed 10 years ago.
I have an IEnumerable<string> which I would like to split into groups of three so if my input had 6 items i would get a IEnumerable<IEnumerable<string>> returned with two items each of which would contain an IEnumerable<string> which my string contents in it.
I am looking for how to do this with Linq rather than a simple for loop
Thanks
var result = sequence.Select((s, i) => new { Value = s, Index = i })
.GroupBy(item => item.Index / 3, item => item.Value);
Note that this will return an IEnumerable<IGrouping<int,string>> which will be functionally similar to what you want. However, if you strictly need to type it as IEnumerable<IEnumerable<string>> (to pass to a method that expects it in C# 3.0 which doesn't support generics variance,) you should use Enumerable.Cast:
var result = sequence.Select((s, i) => new { Value = s, Index = i })
.GroupBy(item => item.Index / 3, item => item.Value)
.Cast<IEnumerable<string>>();
This is a late reply to this thread, but here is a method that doesn't use any temporary storage:
public static class EnumerableExt
{
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> input, int blockSize)
{
var enumerator = input.GetEnumerator();
while (enumerator.MoveNext())
{
yield return nextPartition(enumerator, blockSize);
}
}
private static IEnumerable<T> nextPartition<T>(IEnumerator<T> enumerator, int blockSize)
{
do
{
yield return enumerator.Current;
}
while (--blockSize > 0 && enumerator.MoveNext());
}
}
And some test code:
class Program
{
static void Main(string[] args)
{
var someNumbers = Enumerable.Range(0, 10000);
foreach (var block in someNumbers.Partition(100))
{
Console.WriteLine("\nStart of block.");
foreach (int number in block)
{
Console.Write(number);
Console.Write(" ");
}
}
Console.WriteLine("\nDone.");
Console.ReadLine();
}
}
However, do note the comments below for the limitations of this approach:
If you change the foreach in the test code to
foreach (var block in someNumbers.Partition(100).ToArray())
then it doesn't work any more.
It isn't threadsafe.
I know this has already been answered, but if you plan on taking slices of IEnumerables often, then I recommend making a generic extension method like this:
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int chunkSize)
{
return source.Where((x,i) => i % chunkSize == 0).Select((x,i) => source.Skip(i * chunkSize).Take(chunkSize));
}
Then you can use sequence.Split(3) to get what you want.
(you can name it something else like 'slice', or 'chunk' if you don't like that 'split' has already been defined for strings. 'Split' is just what I happened to call mine.)
Inspired By #dicegiuy30's implementation, I wanted to create a version that only iterates over the source once and doesn't build the whole result set in memory to compensate. Best I've come up with is this:
public static IEnumerable<IEnumerable<T>> Split2<T>(this IEnumerable<T> source, int chunkSize) {
var chunk = new List<T>(chunkSize);
foreach(var x in source) {
chunk.Add(x);
if(chunk.Count <= chunkSize) {
continue;
}
yield return chunk;
chunk = new List<T>(chunkSize);
}
if(chunk.Any()) {
yield return chunk;
}
}
This way I build each chunk on demand. I wish I should avoid the List<T> as well and just stream that that as well, but haven't figured that out yet.
using Microsoft.Reactive you can do this pretty simply and you will iterate only one time through the source.
IEnumerable<string> source = new List<string>{"1", "2", "3", "4", "5", "6"};
IEnumerable<IEnumerable<string>> splited = source.ToObservable().Buffer(3).ToEnumerable();
We can improve #Afshari's solution to do true lazy evaluation. We use a GroupAdjacentBy method that yields groups of consecutive elements with the same key:
sequence
.Select((x, i) => new { Value = x, Index = i })
.GroupAdjacentBy(x=>x.Index/3)
.Select(g=>g.Select(x=>x.Value))
Because the groups are yielded one-by-one, this solution works efficiently with long or infinite sequences.
Mehrdad Afshari's answer is excellent. Here is the an extension method that encapsulates it:
using System.Collections.Generic;
using System.Linq;
public static class EnumerableExtensions
{
public static IEnumerable<IEnumerable<T>> GroupsOf<T>(this IEnumerable<T> enumerable, int size)
{
return enumerable.Select((v, i) => new {v, i}).GroupBy(x => x.i/size, x => x.v);
}
}
I came up with a different approach. It uses a while iterator alright but the results are cached in memory like a regular LINQ until needed.
Here's the code.
public IEnumerable<IEnumerable<T>> Paginate<T>(this IEnumerable<T> source, int pageSize)
{
List<IEnumerable<T>> pages = new List<IEnumerable<T>>();
int skipCount = 0;
while (skipCount * pageSize < source.Count) {
pages.Add(source.Skip(skipCount * pageSize).Take(pageSize));
skipCount += 1;
}
return pages;
}