I have the following Linq
var seq =
GetCollectionA()
.Concat(GetCollectionB())
.Concat(GetCollectionC())
.FirstOrDefault();
If GetCollectionA() returned some objects, the other two methods wrapped in Concat would still run, and for nothing. And each one of those methods return an actual array, not a true Linq-friendly Enumerable. My goal is to have parameters to Concat evaluated when they are actually needed. Wouldn't it be nice if Concat was done to allow lazy-loading lambda expressions like so?
var seq =
GetCollectionA()
.Concat(() => GetCollectionB())
.Concat(() => GetCollectionC())
.FirstOrDefault();
I am thinking about the following workaround, will this work and not call the subsequent collection methods if the element is found in first collection?
var seq =
GetCollectionA()
.Concat(Enumerable.Range(1, 1).SelectMany(_ => GetCollectionB()))
.Concat(Enumerable.Range(1, 1).SelectMany(_ => GetCollectionC()))
.FirstOrDefault();
Is Concat going to actually iterate the sequence anyway instead of putting it on iteration pipeline?
Is there a better way?
Consider using an approach like this to enumerate the collections one at a time:
The key bit is that SmartConcat takes Func rather than the results of the method call (that you are currently using). So it can stop executing as soon as it finds a match.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Test
{
static class ExtraLINQ
{
public static IEnumerable<T> SmartConcat<T>(this IEnumerable<T> source, params Func<IEnumerable<T>>[] extras)
{
foreach (var entry in source)
yield return entry;
foreach (var laterEntries in extras)
{
foreach (var laterEntry in laterEntries())
{
yield return laterEntry;
}
}
}
}
class Program
{
static void Main(string[] args)
{
// Executes both functions
var first = GetCollectionA().Concat(GetCollectionB()).FirstOrDefault();
Console.WriteLine(first);
// Executes only the first
var otherFirst = GetCollectionA().SmartConcat(GetCollectionB).FirstOrDefault();
Console.WriteLine(otherFirst);
Console.ReadLine();
}
private static IEnumerable<int> GetCollectionA()
{
var results = new int[] { 1, 2, 3 };
Console.WriteLine("GetBob");
return results;
}
private static IEnumerable<int> GetCollectionB()
{
var results = new int[] { 4,5,6 };
Console.WriteLine("GetBob4");
return results;
}
}
}
Alternatively, if you are dealing with a reference type, consider:
var result = GetCollectionA().FirstOrDefault() ?? GetCollectionB().FirstOrDefault();
Apparently my ugly looking hack works.
public static void Main()
{
Console.WriteLine("Hello World");
var seq = GetNumbers().Concat(Enumerable.Range(1, 1).SelectMany(_ => GetNumbers())).FirstOrDefault();
Console.WriteLine(seq);
}
static int[] GetNumbers()
{
Console.WriteLine("GetNumbers called");
return new[]{1, 2, 3};
}
}
GetNumbers was called only once
Hello World
GetNumbers called
1
Here is the fiddle
https://dotnetfiddle.net/VDlL79
Related
I want to know weather an IEnumerable parameter to a method is enumerated when I call the method or when I enumerate the return of the method, assuming we have the following code:
IEnumerable<T> ProcessList(IEnumerable<T> list)
{
foreach(var element in list)
{
yield return ProcessElement(element);
}
}
I am mostly curious how to write Where-Linq like extensions.
The list (enumerable) is only enumerated when the result of ProcessList (enum2) is enumerated:
static void Main(string[] args)
{
var enumerable = Enum1();
Console.WriteLine("Enum1 retrieved");
var enum2 = Enum2(enumerable);
Console.WriteLine("Enum2 called");
foreach (var e in enum2)
{
Console.WriteLine(e);
}
}
private static IEnumerable<string> Enum1()
{
Console.WriteLine("Enum1");
yield return "foo";
}
private static IEnumerable<string> Enum2(IEnumerable<string> enumerable)
{
Console.WriteLine("Enum2");
foreach (var s in enumerable)
{
yield return s;
}
}
Gives:
Enum1 retrieved
Enum2 called
Enum2
Enum1
foo
The last three lines are only printed when entering the foreach loop.
Use of the yield keyword means that this snippet of code will evaluate only as needed to provide the results you use. In other words, this will not cause evaluation:
var processed = ProcessList(unprocessed);
The contents of the result list don't matter, so they won't be evaluated yet. However, if you do this:
var processed = ProcessList(unprocessed).ToList();
this will ask it to evaluate the IEnumerable, which will cause it to run your code. Likewise, if you do this:
var processed = ProcessList(unprocessed);
foreach (var x in processed)
{
DoSomething(x);
}
it will run your ProcessElement() method for each element in turn. To take this further, if you do this:
var processed = ProcessList(unprocessed);
foreach (var x in processed.Take(10))
{
DoSomething(x);
}
because you're only using the first 10 items of the result list, it will only run your ProcessElement() method for those 10. The rest will only be evaluated when you come to use them.
i like to call a method without return-type in linq or in extension methods in linq?
Here my class i have situation line this
Class A
{
int i;
public int K
{
get { return i; }
set { i = value; }
}
public void calculate(int z)
{
this.k=z;
}
}
i like to do like this
List<A> sam = new List<A>();
//add elements to this list
var c = sam.Select( s => s.calculate(4) );
this sample only , i like to do like this for my purpose.
You should use List<T>.ForEach here.
sam.ForEach(s => s.calculate(somenumber));
I think you use .Select in your question because you want to get the results(all the instances of A after calling calculate). You can get them directly by the variable sam. ForEach modifies each elements of sam, and the "changes" are applied to the list itself.
If you mean that you want to iterate a sequence (IEnumerable) and invoke code for it, you can inplement an extension method with an action, that is invoked for each item in the sequence, e.g.:
public static void ForEach<T>(this System.Collection.Generic.IEnumerable<T> list, System.Action<T> action)
{
foreach (T item in list)
action(item);
}
This makes sense if you want to invoke small logic (one line) without implementing a foreach() block:
public class MyClass
{
public void DoSomethingInOneLine()
{
// do something
}
}
public static void Test(System.Collections.Generic.IEnumerable<MyClass> list)
{
list.ForEach(item => item.DoSomethingInOneLine());
}
If you don't need the result, you can fill the result with a random value (e.g. false).
var c = sam.Select( s => {s.calculate(4); return false;} );
I recently ran into this issue. I sometimes find I prefer the declerative syntax of LINQ...
this was my call
// wont compile:
from ticket in actualTickets
group ticket by ticket.ID into ticketGroup
select AddToBasket( exhibition, ticketGroup.First(), ticketGroup.Count() );
I couldn't think of a good reason to make AddToBasket() return anything, so I refactored as follows:
var pendingOpperations = from ticket in actualTickets
group ticket by ticket.ID into ticketGroup
select new Action( () => AddToBasket( exhibition, ticketGroup.First(), ticketGroup.Count() ) );
foreach ( var action in pendingOpperations ) action.Invoke();
Using this often:
Generic approach:
from item in sequence
// wrapping statements with lambda
let #void = new Func<bool>(() => {
// whatever you like..
return true;
})()
select item
If you want to do property assignment (bonus: example how to work with HTTP client :-):
..
// inside fluent LINQ query
let client = new HttpClient()
// initialise property and discard result
let #discard = client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes("user:pass")))
// now work with initialised client according to your logic..
select client.GetAsync("url").Result.Content.ReadAsStringAsync().Result
I had the same requirement recently, call the action reactively and I write a Do() stream processing function for 1) wrapping the action into a functor with a return value and 2) selecting on the stream.
public static IEnumerable<TSource> Do<TSource>(this IEnumerable<TSource> source,
Action<TSource> action) {
TSource doSelector(TSource src) {
action.Invoke(src);
return src;
}
return source
.Select(it => doSelector(it));
}
Please note that this utility function still has to convert the stream into List() to literally call the action for each stream item.
var numbers = new List<int> { 1, 2, 3 };
var sum = 0;
numbers
.Do(it => { sum += it; })
.ToList();
I've the following code:
var e = someList.GetEnumerator();
var a = new List<Foo>();
var b = new List<Foo>();
while(e.MoveNext()) {
if(CheckCondition(e.Current)) {
b.Add(e.Current);
break;
}
a.Add(e.Current);
}
while(e.MoveNext())
b.Add(e.Current)
This looks ugly. Basically, iterate through a list and add elements to one list until some condition kicks in, and add the rest to another list.
Is there a better way e.g. using linq ? CheckCondition() is expensive, and the lists can be huge so I'd prefer to not do anything that iterates the lists twice.
Here's a solution that's going to enumerate the list twice, but it won't check the condition the second time, so it should be faster:
var a = someList.TakeWhile(x => !CheckCondition(x)).ToList();
var b = someList.Skip(a.Count).ToList();
If someList implements IList<T>, each item will actually be enumerated only once, so there won't be any penalty.
I thought Skip was optimized for the case of IList<T>, but apparently it's not... However you could easily implement your own Skip method that uses this optimization (see Jon Skeet's article about this)
It would actually be more elegant if there was a TakeUntil method... we can easily create it:
public static IEnumerable<TSource> TakeUntil<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach(var item in source)
{
if (predicate(item))
break;
yield return item;
}
}
With this method, the code becomes:
var a = someList.TakeUntil(CheckCondition).ToList();
var b = someList.Skip(a.Count).ToList();
I didn't want to change Ani's answer, but here's a slight simplification.
var listToBeAdded = a;
foreach (var item in someList)
{
if (listToBeAdded == a && CheckCondition(item))
listToBeAdded = b;
listToBeAdded.Add(item);
}
Personally, I don't think there's any need for LINQ here.
I would do something like:
bool conditionHit = false;
foreach (var item in someList)
{
if (!conditionHit)
conditionHit = CheckCondition(item);
var listToBeAdded = conditionHit ? b : a;
listToBeAdded.Add(item);
}
If someList is a concrete List<T> then this will only need a single pass through each element:
var a = someList.TakeWhile(x => !CheckCondition(x)).ToList();
var b = someList.GetRange(a.Count, someList.Count - a.Count);
This will end up going over the items in the first list more than once, but only calls through CheckCondition the first time:
var a = someList.TakeWhile(e => !CheckCondition(e));
var b = someList.Skip(a.Count());
Try this (not re-using Linq's built-in methods(known for rewinding the iterators)), just reusing the OP's logic (which I believe is performant, it doesn't re-evaluate condition on next half of list) and packing it in a neat extension method and Tuple:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Craft
{
class Act
{
static void Main(string[] args)
{
var a = new List<string>
{ "I", "Love", "You", "More", "Today", "Than", "Yesterday" };
var tx = a.SplitByCondition(s => s == "More");
foreach (var s in tx.Item1)
Console.WriteLine("First Half : {0}", s);
foreach (var s in tx.Item2)
Console.WriteLine("Second Half : {0}", s);
Console.ReadLine();
}
}//Act
public static class Helper
{
public static Tuple<List<T>, List<T>> SplitByCondition<T>
(this IEnumerable<T> t, Func<T, bool> terminator)
{
var tx = new Tuple<List<T>, List<T>>
(new List<T>(), new List<T>());
var iter = t.GetEnumerator();
while (iter.MoveNext())
{
if (terminator(iter.Current))
{
tx.Item2.Add(iter.Current);
break;
}
tx.Item1.Add(iter.Current);
}
while (iter.MoveNext())
tx.Item2.Add(iter.Current);
return tx;
}
}//Helper
}//Craft
Output:
First Half : I
First Half : Love
First Half : You
Second Half : More
Second Half : Today
Second Half : Than
Second Half : Yesterday
Imagine you would want to select all elements of one sequence all, except elements contained in sequence exceptions and single element otherException.
Is there some better way to do this than? I'd like to avoid creating new array, but I couldn't find a method on the sequence that concats it with a single element.
all.Except(exceptions.Concat(new int[] { otherException }));
complete source code for completeness' sake:
var all = Enumerable.Range(1, 5);
int[] exceptions = { 1, 3 };
int otherException = 2;
var result = all.Except(exceptions.Concat(new int[] { otherException }));
An alternative (perhaps more readable) would be:
all.Except(exceptions).Except(new int[] { otherException });
You can also create an extension method that converts any object to an IEnumerable, thus making the code even more readable:
public static IEnumerable<T> ToEnumerable<T>(this T item)
{
return new T[] { item };
}
all.Except(exceptions).Except(otherException.ToEnumerable());
Or if you really want a reusable way to easily get a collection plus one item:
public static IEnumerable<T> Plus<T>(this IEnumerable<T> collection, T item)
{
return collection.Concat(new T[] { item });
}
all.Except(exceptions.Plus(otherException))
I would like to call FindLast on a collection which implements IEnumerable, but FindLast is only available for List. What is the best solution?
The equivalent to:
var last = list.FindLast(predicate);
is
var last = sequence.Where(predicate).LastOrDefault();
(The latter will have to check all items in the sequence, however...)
Effectively the "Where()" is the Find part, and the "Last()" is the Last part of "FindLast" respectively. Similarly, FindFirst(predicate) would be map to sequence.Where(predicate).FirstOrDefault() and FindAll(predicate) would be sequence.Where(predicate).
How about with LINQ-to-Objects:
var item = data.LastOrDefault(x=>x.Whatever == "abc"); // etc
If you only have C# 2, you can use a utility method instead:
using System;
using System.Collections.Generic;
static class Program {
static void Main() {
int[] data = { 1, 2, 3, 4, 5, 6 };
int lastOdd = SequenceUtil.Last<int>(
data, delegate(int i) { return (i % 2) == 1; });
}
}
static class SequenceUtil {
public static T Last<T>(IEnumerable<T> data, Predicate<T> predicate) {
T last = default(T);
foreach (T item in data) {
if (predicate(item)) last = item;
}
return last;
}
}
you can add you collection to a new List by passing it to List<> constructor.
List<MyClass> myList = new List<MyClass>(MyCol);
myList.FindLast....
Use the extension method Last()
which is located in the namespace System.Linq.
Your question is invalid because a collection has no last element. A more specialized collection that does have a complete ordering is a list. A more specialized collection that does not have an ordering is a dictionary.