LINQ Transformation Function - c#

Just one curious question from me, is there any transformation function in linq. I mean if i have List<int> or List<Foo>, i would like to change the elements at say index x or whoever satisfy the condition in Where.

If you're looking to conditionally project a Foo to another Foo (leaving others untouched), you can do something like:
IEnumerable<Foo> foos = ...
var transformed = foos.Select(foo => myCondition(foo) ? transform(foo) : foo);
On the other hand, if you only want to project Foos that match the condition:
var transformed = foos.Where(foo => myCondition(foo))
.Select(foo => transform(foo));
Do note that both of these return new sequences - LINQ isn't normally used to modify existing collections. You could of course materialize the results into a collection, overwriting an existing variable if necessary.
// assuming the transform is from Foo -> Foo
foos = foos.Select(foo => transform(foo)).ToList();
Since you specifically mention lists, there is another non-LINQ immediate-execution alternative to the first query - the List<T>.ConvertAll method:
List<Foo> foos = ...
// implicitly List<Foo> assuming the transform is from Foo -> Foo
var transformed = foos.ConvertAll
(foo => myCondition(foo) ? transform(foo) : foo);
EDIT: Sounds like you're looking for a "ReplaceWhere" method - as far as I know, there is no direct framework method that replaces the elements of a list based on a predicate. It's easy to write one yourself though:
/// <summary>
/// Replaces items in a list that match the specified predicate,
/// based on the specified selector.
/// </summary>
public static void ReplaceWhere<T>(this IList<T> list,
Func<T, bool> predicate,
Func<T, T> selector)
{
// null-checks here.
for (int i = 0; i < list.Count; i++)
{
T item = list[i];
if (predicate(item))
list[i] = selector(item);
}
}
Usage:
List<int> myList = ...
myList.ReplaceWhere(i => i > 0, i => i * i);

You could certainly write a transformation function:
// allows you to transform every element
public static List<T> TransformAll<T>(this List<T> list,
Func<T, T> converter)
{
for (int i = 0; i < list.Count; i++)
{
list[i] = converter(list[i]);
}
return list;
}
// allows you to transform every element based on its index
public static List<T> TransformAll<T>(this List<T> list,
Func<T, int, T> converter)
{
for (int i = 0; i < list.Count; i++)
{
list[i] = converter(list[i], i);
}
return list;
}
// allows you to transform chosen elements
public static List<T> TransformWhere<T>(this List<T> list,
Func<T, bool> predicate,
Func<T, T> converter)
{
for (int i = 0; i < list.Count; i++)
{
T item = list[i];
if (predicate(item))
list[i] = converter(item);
}
return list;
}
// allows you to transform chosen elements based on its index
public static List<T> TransformWhere<T>(this List<T> list,
Func<T, int, bool> predicate,
Func<T, int, T> converter)
{
for (int i = 0; i < list.Count; i++)
{
T item = list[i];
if (predicate(item, i))
list[i] = converter(item, i);
}
return list;
}
Note that I made all my functions return the passed-in list so that you can use them fluently, like list.TransformAll(x => x + 2).Sum().

Related

How to AddRange many lists of IEnumerable<IEnumerable<T>> into IEnumerable<List<int>>

I have those functions
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> items, int count)
{
int i = 0;
foreach (var item in items)
{
if (count == 1)
yield return new T[] { item };
else
{
foreach (var result in GetPermutations(items.Skip(i + 1), count - 1))
yield return new T[] { item }.Concat(result);
}
++i;
}
}
public static List<List<int>> GetAllValidCombinations(List<int> items)
{
var finalList = new List<List<int>>();
switch (items.Count)
{
case 1:
finalList.Add(items);
break;
case 3:
finalList.AddRange(GetPermutations(items, 2));
finalList.AddRange((List<List<int>>)GetPermutations(items, 3));
break;
}
return finalList;
}
and i want to get an List<List> from GetAllValidCombinations.
In the case 3 of GetAllValidCombinationsin the first line im getting:
Error CS1503 Argument 1: cannot convert from 'System.Collections.Generic.IEnumerable<System.Collections.Generic.IEnumerable>' to 'System.Collections.Generic.IEnumerable<System.Collections.Generic.List>'
and if i try the second line im getting error Specified cast is not valid
How i can do this cast in one line?
Sweepers answer is on the money, also you could refactor it a little by only using lists in the inner collection and making it completely generic.
public static IEnumerable<List<T>> GetPermutations<T>(List<T> items, int count)
{
for (var index = 0; index < items.Count; index++)
if (count == 1)
yield return new List<T> { items[index] };
else
foreach (var result in GetPermutations(items.Skip(index + 1).ToList(), count - 1))
yield return new List<T> { items[index] }
.Concat(result)
.ToList();
}
public static IEnumerable<List<T>> GetAllValidCombinations<T>(List<T> items)
{
if (items.Count == 1)
return new List<List<T>> {items};
if (items.Count == 3)
return GetPermutations(items, 2)
.Concat(GetPermutations(items, 3));
return Enumerable.Empty<List<T>>();
}
Usage
var results = GetAllValidCombinations(new List<int>() {1, 2, 3});
foreach (var result in results)
Console.WriteLine(string.Join(",",result));
Output
1,2
1,3
2,3
1,2,3
Full Demo Here
AddRange expects an IEnumerable of Lists, but you have given it an IEnumerable of IEnumerables. Those IEnumerable could be anything, not necessarily lists, right? They could be sets or arrays or some other type that I wrote, that just happens to implement IEnumerable<T>... This is the reason why the compiler gives you the error.
And as you have written GetPermutations, we can see that they are actually arrays of T! So you are trying to add a bunch of arrays to a list of lists! That doesn't make much sense, does it?
Fortunately, ToList converts any IEnumerable to a List. You should apply this method to each IEnumerable nested inside the outer IEnumerable using Select:
var enumerableOfEnumerables = GetPermutations(items, 2);
finalList.AddRange(enumerableOfEnumerables.Select(x => x.ToList()));

verify cummulative sum verify property efficiently with LINQ

I would like to verify if the sum of the elements (which are non-negativ) of my list isinferior to some values. And I don't want to calculate the the whole sum it is not necessary.(if we prove that the sum of the first element don't respect the property, we stop the computation)
So I would like a LINQ command that verify each element of the cummulative sum is inferior to some value as long as it see that the ineqality hold.
var b = a.Aggregate(new List<int> { 0 }, (ls, x) => { ls.Add(x + ls.Last()); return ls; }).All(x => x < 4);
This method doesn't work. All stop when it see that the ith element of the cummulative sum doesn't safisty the property but the whole cummulative sum is compute.
Have you a better way to do that? (I know we can do that efficiently with loop but I want to do that with LINQ)
if I use a loop:
var s = 0;
var b = true;
foreach(var x in list)
{
s=s+x;
if(s>4){ b= false; break;}
}
Thank you
You don't need to use a LINQ method to do what you want. You can write your own using enumerators and loops. After all, LINQ-to-Objects operations themselves are implemented using loops. For example TakeWhile is implemented as an iterator that loops over the source and yields matching elements :
static IEnumerable<TSource> TakeWhileIterator<TSource>(IEnumerable<TSource> source, Func<TSource, int, bool> predicate) {
int index = -1;
foreach (TSource element in source) {
checked { index++; }
if (!predicate(element, index)) break;
yield return element;
}
}
The downside is that this generates a state machine for the iterator and returns all matching elements, whether they are used or not.
You can write your own extension method that calculates the sum in a loop and returns true if the loop completes without reaching the limit :
public static bool SumBelow(this IEnumerable<int> source, int limit)
{
int sum=0;
foreach (var element in source)
{
sum+=element;
if (sum>limit)
{
return false;
}
}
return true;
}
And use it as an extension method :
var isSumBelow = someEnumerable.SumBelow(5);
Why not a generic method ?
There's no way to specify an operator constraint or an IAddable interface, which is why Sum() itself is implemented for each type separately, eg :
public static int Sum(this IEnumerable<int> source) {
if (source == null) throw Error.ArgumentNull("source");
int sum = 0;
checked {
foreach (int v in source) sum += v;
}
return sum;
}
The functional way
Passing the accumulator and condition checker as functions can be used to create one generic, reusable method that can work with any transormation and condition :
public static bool AccWithinLimit<T>(
this IEnumerable<T> source,
Func<T,T,T> accumulator,
Func<T,bool> terminator,
T seed=default)
{
T total=seed;
foreach (var element in source)
{
total = accumulator(element,total);
if (terminator(total))
{
return false;
}
}
return true;
}
This can be used to check for partial sums with integer arrays :
var myArray=new []{1,2,3};
var limit = 5;
var totalBelowLimit = myArray.AccWithinLimit(myArray,
(sum,elm)=>sum+elm,
sum=>sum>limit);
Or partial products with a list of doubles:
var myList = new List<double>{1.0, 2.0, 3.0};
var limit = 10;
var totalBelowLimit = myList.AccWithinLimit(myArray,
(sum,elm)=>sum*elm,
sum=>sum>limit,
1);
You can use TakeWhile to take items from the list until the sum exeeds some value
public void TestTakeWhileCumulativeSum()
{
int[] numbers = new[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
int maxCumulativeSum = 5;
int previous = 0;
var result = numbers.TakeWhile(n => (previous = n + previous) <= maxCumulativeSum);
Assert.AreEqual(result.Count(), 5);
}

Select elements in an array where elements in another array are true

As I said in the title: I need to select elements in an array in the position where elements in another array are true. The same result I'd have with Matlab command:
output = array1(array2);
Where array2 is an array of bools.
I'm lost in Linq at the moment :)
there's an overload of Where extension method taking an Func<TSource, int, bool> predicate as second argument.
The int paremeter in the Func<TSource, int, bool> is the index of the source.
output = array1.Where((x, index) => array2[index]);
Try this:
var bools = new[] { true, false };
var elements = new[] { 1, 2 };
var result = elements
.Take(bools.Length)
.Where((e, index) => bools[index]).ToList();
The Take method ensures that the element search is made in the index range of the bools array.
For the general case, you could write a custom extension method - for example:
public static IEnumerable<T> WhereEnabled<T>(
this IEnumerable<T> source,
IEnumerable<bool> flags)
{
using(var sourceIter = source.GetEnumerator())
using(var flagIter = flags.GetEnumerator())
{
while(sourceIter.MoveNext() && flagIter.MoveNext())
{
if (flagIter.Current) yield return sourceIter.Current;
}
}
}
then just:
var enabled = array1.WhereEnabled(array2);
perhaps with the vector specialization:
public static IEnumerable<T> WhereEnabled<T>(
this T[] source,
bool[] flags)
{
int max = Math.Min(source.Length, flags.Length);
for (int i = 0; i < max; i++ )
{
if (flags[i]) yield return source[i];
}
}

Split an IEnumerable<T> into fixed-sized chunks (return an IEnumerable<IEnumerable<T>> where the inner sequences are of fixed length) [duplicate]

This question already has answers here:
Create batches in LINQ
(21 answers)
Split List into Sublists with LINQ
(34 answers)
Closed 5 years ago.
I want to take an IEnumerable<T> and split it up into fixed-sized chunks.
I have this, but it seems inelegant due to all the list creation/copying:
private static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> items, int partitionSize)
{
List<T> partition = new List<T>(partitionSize);
foreach (T item in items)
{
partition.Add(item);
if (partition.Count == partitionSize)
{
yield return partition;
partition = new List<T>(partitionSize);
}
}
// Cope with items.Count % partitionSize != 0
if (partition.Count > 0) yield return partition;
}
Is there something more idiomatic?
EDIT: Although this has been marked as a duplicate of Divide array into an array of subsequence array it is not - that question deals with splitting an array, whereas this is about IEnumerable<T>. In addition that question requires that the last subsequence is padded. The two questions are closely related but aren't the same.
You could try to implement Batch method mentioned above on your own like this:
static class MyLinqExtensions
{
public static IEnumerable<IEnumerable<T>> Batch<T>(
this IEnumerable<T> source, int batchSize)
{
using (var enumerator = source.GetEnumerator())
while (enumerator.MoveNext())
yield return YieldBatchElements(enumerator, batchSize - 1);
}
private static IEnumerable<T> YieldBatchElements<T>(
IEnumerator<T> source, int batchSize)
{
yield return source.Current;
for (int i = 0; i < batchSize && source.MoveNext(); i++)
yield return source.Current;
}
}
I've grabbed this code from http://blogs.msdn.com/b/pfxteam/archive/2012/11/16/plinq-and-int32-maxvalue.aspx.
UPDATE: Please note, that this implementation not only lazily evaluates batches but also items inside batches, which means it will only produce correct results when batch is enumerated only after all previous batches were enumerated. For example:
public static void Main(string[] args)
{
var xs = Enumerable.Range(1, 20);
Print(xs.Batch(5).Skip(1)); // should skip first batch with 5 elements
}
public static void Print<T>(IEnumerable<IEnumerable<T>> batches)
{
foreach (var batch in batches)
{
Console.WriteLine($"[{string.Join(", ", batch)}]");
}
}
will output:
[2, 3, 4, 5, 6] //only first element is skipped.
[7, 8, 9, 10, 11]
[12, 13, 14, 15, 16]
[17, 18, 19, 20]
So, if you use case assumes batching when batches are sequentially evaluated, then lazy solution above will work, otherwise if you can't guarantee strictly sequential batch processing (e.g. when you want to process batches in parallel), you will probably need a solution which eagerly enumerates batch content, similar to one mentioned in the question above or in the MoreLINQ
It feels like you want two iterator blocks ("yield return methods"). I wrote this extension method:
static class Extensions
{
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> items, int partitionSize)
{
return new PartitionHelper<T>(items, partitionSize);
}
private sealed class PartitionHelper<T> : IEnumerable<IEnumerable<T>>
{
readonly IEnumerable<T> items;
readonly int partitionSize;
bool hasMoreItems;
internal PartitionHelper(IEnumerable<T> i, int ps)
{
items = i;
partitionSize = ps;
}
public IEnumerator<IEnumerable<T>> GetEnumerator()
{
using (var enumerator = items.GetEnumerator())
{
hasMoreItems = enumerator.MoveNext();
while (hasMoreItems)
yield return GetNextBatch(enumerator).ToList();
}
}
IEnumerable<T> GetNextBatch(IEnumerator<T> enumerator)
{
for (int i = 0; i < partitionSize; ++i)
{
yield return enumerator.Current;
hasMoreItems = enumerator.MoveNext();
if (!hasMoreItems)
yield break;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}
Maybe?
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> items, int partitionSize)
{
return items.Select((item, inx) => new { item, inx })
.GroupBy(x => x.inx / partitionSize)
.Select(g => g.Select(x => x.item));
}
There is an already implemented one too: morelinq's Batch.
Craziest solution (with Reactive Extensions):
public static IEnumerable<IList<T>> Partition<T>(this IEnumerable<T> items, int partitionSize)
{
return items
.ToObservable() // Converting sequence to observable sequence
.Buffer(partitionSize) // Splitting it on spececified "partitions"
.ToEnumerable(); // Converting it back to ordinary sequence
}
I know that I changed signature but anyway we all know that we'll have some fixed size collection as a chunk.
BTW if you will use iterator block do not forget to split your implementation into two methods to validate arguments eagerly!
For elegant solution, You can also have a look at MoreLinq.Batch.
It batches the source sequence into sized buckets.
Example:
int[] ints = new int[] {1,2,3,4,5,6};
var batches = ints.Batch(2); // batches -> [0] : 1,2 ; [1]:3,4 ; [2] :5,6
public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> items,
int partitionSize)
{
int i = 0;
return items.GroupBy(x => i++ / partitionSize).ToArray();
}
How about the partitioner classes in the System.Collections.Concurrent namespace?
You can do this using an overload of Enumerable.GroupBy and taking advantage of integer division.
return items.Select((element, index) => new { Element = element, Index = index })
.GroupBy(obj => obj.Index / partitionSize, (_, partition) => partition);

Optimal LINQ query to get a random sub collection - Shuffle

Please suggest an easiest way to get a random shuffled collection of count 'n' from a collection having 'N' items. where n <= N
Further to mquander's answer and Dan Blanchard's comment, here's a LINQ-friendly extension method that performs a Fisher-Yates-Durstenfeld shuffle:
// take n random items from yourCollection
var randomItems = yourCollection.Shuffle().Take(n);
// ...
public static class EnumerableExtensions
{
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source)
{
return source.Shuffle(new Random());
}
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random rng)
{
if (source == null) throw new ArgumentNullException("source");
if (rng == null) throw new ArgumentNullException("rng");
return source.ShuffleIterator(rng);
}
private static IEnumerable<T> ShuffleIterator<T>(
this IEnumerable<T> source, Random rng)
{
var buffer = source.ToList();
for (int i = 0; i < buffer.Count; i++)
{
int j = rng.Next(i, buffer.Count);
yield return buffer[j];
buffer[j] = buffer[i];
}
}
}
Another option is to use OrderBy and to sort on a GUID value, which you can do so using:
var result = sequence.OrderBy(elem => Guid.NewGuid());
I did some empirical tests to convince myself that the above actually generates a random distribution (which it appears to do). You can see my results at Techniques for Randomly Reordering an Array.
This has some issues with "random bias" and I am sure it's not optimal, this is another possibility:
var r = new Random();
l.OrderBy(x => r.NextDouble()).Take(n);
Shuffle the collection into a random order and take the first n items from the result.
A bit less random, but efficient:
var rnd = new Random();
var toSkip = list.Count()-n;
if (toSkip > 0)
toSkip = rnd.Next(toSkip);
else
toSkip=0;
var randomlySelectedSequence = list.Skip(toSkip).Take(n);
Just needed to do that today. Here's my stab at it:
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> enumerable)
=> enumerable.Shuffle(new Random());
private static IEnumerable<T> Shuffle<T>(this IEnumerable<T> enumerable, Random random)
=> enumerable
.Select(t => (t, r: random.Next())) // zip with random value
.OrderBy(tr => tr.r)
.Select(tr => tr.t);
The main idea here is the "zip" but without using Zip since we only want to iterate the enumerable once. Inside the sort, each element of the original enumerable has the same "value".
I write this overrides method:
public static IEnumerable<T> Randomize<T>(this IEnumerable<T> items) where T : class
{
int max = items.Count();
var secuencia = Enumerable.Range(1, max).OrderBy(n => n * n * (new Random()).Next());
return ListOrder<T>(items, secuencia.ToArray());
}
private static IEnumerable<T> ListOrder<T>(IEnumerable<T> items, int[] secuencia) where T : class
{
List<T> newList = new List<T>();
int count = 0;
foreach (var seed in count > 0 ? secuencia.Skip(1) : secuencia.Skip(0))
{
newList.Add(items.ElementAt(seed - 1));
count++;
}
return newList.AsEnumerable<T>();
}
Then, I have my source list (all items)
var listSource = p.Session.QueryOver<Listado>(() => pl)
.Where(...);
Finally, I call "Randomize" and I get a random sub-collection of items, in my case, 5 items:
var SubCollection = Randomize(listSource.List()).Take(5).ToList();
Sorry for ugly code :-), but
var result =yourCollection.OrderBy(p => (p.GetHashCode().ToString() + Guid.NewGuid().ToString()).GetHashCode()).Take(n);

Categories