Adding an item to a collection using LINQ

I am trying to process some list with a functional approach in C #.

The idea is that I have a collection of Tuple<T,double> , and I want to change Item 2 some T element.

The functional way to do this, since the data is immutable, is to take a list, filter for all elements where the element is different from the one that needs to be changed, and add a new tuple with new values.

My problem is that I do not know how to add an element at the end. I would like to do:

 public List<Tuple<T,double>> Replace(List<Tuple<T,double>> collection, T term,double value) { return collection.Where(x=>!x.Item1.Equals(term)).Append(Tuple.Create(term,value)); } 

But there is no Append method. Is there anything else?

+4
source share
7 answers

I believe you are looking for Concat .

It combines two IEnumerable<T> together, so you can create it with one element to attach.

 public List<Tuple<T,double>> Replace(List<Tuple<T,double>> collection, T term,double value) { var newItem = new List<Tuple<T,double>>(); newItem.Add(new Tuple<T,double>(term,value)); return collection.Where(x=>!x.Item1.Equals(term)).Concat(newItem).ToList(); } 
+6
source

LINQ is not for mutation. Functional programming prevents mutation.

In this way:

 public IEnumerable<Tuple<T,double>> Extend(IEnumerable<Tuple<T,double>> collection, T term,double value) { foreach (var x in collection.Where(x=>!x.Item1.Equals(term))) { yield return x; } yield return Tuple.Create(term,value); } 
+3
source

This should do what you want (although it uses the mutation internally, it feels functional in terms of subscribers):

 public List<Tuple<T, double>> Replace(List<Tuple<T, double>> collection, T term, double value) { var result = collection.Where(x => !x.Item1.Equals(term)).ToList(); result.Add(Tuple.Create(term, value)); return result; } 

An alternative way to do this is to use "map" ( select in LINQ):

 public List<Tuple<T, double>> Replace(List<Tuple<T, double>> collection, T term, double value) { return collection.Select(x => Tuple.Create( x.Item1, x.Item1.Equals(term) ? value : x.Item2)).ToList(); } 

But this may give you different results than your original intention. Although, for me, this is what I think when I see a method called Replace , which is a replacement for the place.

UPDATE

You can also create what you want:

 public List<Tuple<T, double>> Replace(List<Tuple<T, double>> collection, T term, double value) { return collection. Where(x => !x.Item1.Equals(term)). Append(Tuple.Create(term, value)). ToList(); } 

Using Concat as indicated by Oded:

 public static class EnumerableEx { public static IEnumerable<T> Append<T>(this IEnumerable<T> source, T item) { return source.Concat(new T[] { item }); } } 
+1
source

One way is to use .Concat() , but for the second argument you need to list, not just one element. To create an array with a single element, it works, but it is complicated to compile.

It is better to write your own extension method for this.

One way is to create a new List<T> and add items from the first list, and then items from the second list. However, it is better to use yield -keyword instead, so you do not need to create a list, and the enumerable will be evaluated in a lazy way:

 public static class EnumerableExtensions { public static IEnumerable<T> Concat<T>(this IEnumerable<T> list, T item) { foreach (var element in list) { yield return element; } yield return item; } } 
+1
source

If you want to use the add-on package, check out MoreLinq available on Nuget. This provides a new overload of Concat Function:

 public static IEnumerable<T> Concat<T>(this IEnumerable<T> head, T tail); 

This function performs exactly what was proposed, for example. you could do

 var myEnumerable = Enumerable.Range(10, 3); // Enumerable of values 10, 11, 12 var newEnumerable = myEnumerable.Concat(3); // Enumerable of values 10, 11, 12, 3 

And, if you like LINQ, you'll probably enjoy many other new features!

Also, as the MoreLinq Github page pointed out , the function

 public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> source, TSource element); 

with a different name, but the same functionality is available in .NET Core, so it’s possible that we will see it for C # in the future.

+1
source

The closest answer I could find came from this post and:

 return collection.Where(x=>!x.Item1.Equals(term)).Concat(new[]{Tuple.Create(term,value)}); 
0
source

It looks like .NET 4.7.1 adds the append LINQ statement that you want. Unlike Concat, it takes one value.

By the way, if you declare a generic method, you must specify the type parameter after its name:

 public List<Tuple<T, double>> Replace<T>(List<Tuple<T, double>> collection, T term, double value) { return collection.Where(x => !x.Item1.Equals(term)) .Append(Tuple.Create(term, value)) .ToList(); } 
0
source

Source: https://habr.com/ru/post/1381865/


All Articles