My linq select does not work, my foreach does - c#

I have the following LINQ Select which does not work.
Data.Select(d => d.Value.IsDirty = true); //-- Not working
My longer workaround does.
foreach (var d in Data)
d.Value.IsDirty = true;
Why does my first code not work?

Projection functions like Select, Where, etc. define queries. Simply calling Select does not actually do anything until the query is evaluated (almost certainly, at some point, by a foreach).
If you were to do something to force execution of the query (calling Count, for instance), you'd see it take effect.
It is, however, a bit of an abuse. These functions aren't specifically intended for state-altering operations.

Select() returns an IEnumerable<…>, which has the ability to iterate over the input and invoke the code in question, but doesn't actually do so until you enumerate it in some manner:
Data.Select(d => d.Value.IsDirty = true).ToList();
or
foreach (var _ in Data.Select(d => d.Value.IsDirty = true))
; // Do nothing
However, given that they perform side effects (obviously the intent here), both of the above are bad karma. Don't use them. Your original foreach is the only sensible choice.

Calling Select does not cause the side effect you need, even if you force execution by iterating over the elements.
If you want the side effect you have to do foreach.
For example:
class MyValue
{
public MyValue(bool flag) { Flag = flag; }
public bool Flag { get; set; }
}
class MyValueContainer
{
public MyValueContainer(MyValue val) { MyVal = val; }
public MyValue MyVal { get; set; }
}
class Program
{
static void Main(string[] args)
{
var someList = new List<MyValueContainer>();
someList.Add(new MyValueContainer(new MyValue(true)));
someList.Add(new MyValueContainer(new MyValue(true)));
someList.Add(new MyValueContainer(new MyValue(false)));
someList.Add(new MyValueContainer(new MyValue(true)));
var trueCount = someList.Count(x => x.MyVal.Flag); // 3
var falseCount = someList.Count(x => !x.MyVal.Flag); // 1
// try causing side effect by calling Select
someList.Select(x => x.MyVal.Flag = false);
// force execution. call Count
trueCount = someList.Count(x => x.MyVal.Flag); // still 3... no side effect.
falseCount = someList.Count(x => !x.MyVal.Flag); // still 1... no side effect.
foreach (var x in someList)
x.MyVal.Flag = false;
trueCount = someList.Count(x => x.MyVal.Flag); // 0... side effect seen.
falseCount = someList.Count(x => !x.MyVal.Flag); // 4... side effect seen.
}
}

Related

Changing all values in a lambda/LINQ

I have a dictionary of a list of objects that looks like this
class Client
{
public int Hash { get; set; }
public bool Active { get; set; }
}
var ClientsDict = new Dictionary<string, List<Client>>();
I have no problem setting a single record value in the list
ClientsDict[userId].First(a => a.Hash == hash).Active = true;
How do I do the inverse of that and set all the others in the list to false?
ClientsDict[userId].All().Active = false; //cannot resolve symbol
Note: I wanna avoid a foreach
EDIT:
ClientsDict[userId].ForEach(a => a.Active = false); //this works
If you're mutating things you shouldn't be expressing it as a LINQ transformation. Just use a regular foreach loop:
foreach(var client in ClientsDict[userId])
{
client.Active = false;
}
You can also use the List<T>.ForEach method, but I would advise against it.
Use the Where LINQ method to express the opposite condition and loop over the resulting set:
foreach(var client in ClientsDict[userId].Where(c => c.Hash != hash))
{
client.Active = false;
}
EDIT: the ForEach() method version for comparison:
ClientsDict[userId]
.Where(c => c.Hash != hash)
.ToList()
.ForEach(c => c.Active = false);
I'm usually not a fan of using the ForEach() method, but I have to admit that it doesn't look too bad here. That said, because the method is only available on List<T>, you're forced to call .ToList().
For a more philosophical discussion on whether its use is a good idea or not, see here: “foreach” vs “ForEach”.

Using nested Any() method

Suppose you wanna test or compare the equality of two Vectors.
Suppose you have:
string[] models = {"ModelOne", "ModelTwo", "ModeThree"};
And another one that you don't know for sure what will be inside of it, but you believe that it will contain the same elements like models owner above.
I have this method to make this verification and I use it in a Unit test passing the vector models presented above.
public bool TemplateForDependenciesTests (string[] v)
{
var dependency = new Dependencies();
var result = dependency.GetByReferencedModel(typeof(T).ToString());
//foreach (var i in result)
//{
//if ((v.Any(model => model == i.ReferencingModelName)))
//return false;
//}
return result.Any(x => (v.Any(model => model == x.ReferencingModelName)));
}
the result variable will hold the return of this method:
public IEnumerable<Dependency> GetByReferencedModel(string referencedModelName)
{
return this.dependencies
.Where(d => d.ReferencedModelName == referencedModelName);
}
The question is: How can I make that return statement in TemplateForDependenciesTests() work nicely and in a way I can snoop that indeed it is doing what I expect, because till now I moved some stones here and there, but it appears not doing what I want?
It looks like you're just trying to see if any member of result has a ReferencingModelName that's in the models collection. Seems like this would do it:
return result.Select(x => x.ReferencingModelName).Intersect(v).Any();
Now, if you want to snoop to see if it's really doing what you expect:
var intersection = result.Select(x => x.ReferencingModelName).Intersect(v).ToList();
// now you can examine the contents of the intersection list
// and you can return the result
return intersection.Any();
You might even go one step further:
var result = dependency.GetByReferencedModel(typeof(T).ToString()).ToList();
var names = result.Select(x => x.ReferencingModelName).ToList();
var intersection = names.Intersect(v).ToList();
return intersection.Any();
With that, you can examine the results of each step, and you should be able to see where the error exists.
Order doesn't matter to Intersect. That is if you have:
var x = new string["a", "b", "c"];
var y = new string["c", "b"];
var z = new string["b", "c"];
Then x.Intersect(y) == y.Intersect(x) == x.Intersect(z) == y.Intersect(z), etc.
You could make your lambdas easier to debug by making them multi-line statements. E.g. you could put breakpoints all over this to see exactly what's happening.
var resultList = result.ToList();
return resultList.Any(x =>
{
bool outer = v.Any(model =>
{
bool inner = model == x.ReferencingModelName;
return inner;
});
return outer;
});
I'll also note that with things like ToLookup or ToDictionary, and HashSet<T>, you could make all of these lookups much faster and more intuitively-coded.

"Merging" a stream of streams to produce a stream of the latest values of each

I have an IObservable<IObservable<T>> where each inner IObservable<T> is a stream of values followed by an eventual OnCompleted event.
I would like to transform this into an IObservable<IEnumerable<T>>, a stream consisting of the latest value from any inner stream that is not completed. It should produce a new IEnumerable<T> whenever a new value is produced from one of the inner streams (or an inner stream expires)
It is most easily shown with a marble diagram (which I hope is comprehensive enough):
input ---.----.---.----------------
| | '-f-----g-|
| 'd------e---------|
'a--b----c-----|
result ---a--b-b--c-c-c-e-e-e---[]-
d d d e f g
f f
([] is an empty IEnumerable<T> and -| represents the OnCompleted)
You can see that it slightly resembles a CombineLatest operation.
I have been playing around with Join and GroupJoin to no avail but I feel that that is almost certainly the right direction to be heading in.
I would like to use as little state as possible in this operator.
Update
I have updated this question to include not just single-valued sequences - the resultant IObservable<IEnumerable<T>> should include only the latest value from each sequence - if a sequence has not produced a value, it should not be included.
Here's a version based your solution yesterday, tweaked for the new requirements. The basic idea is to just put a reference into your perishable collection, and then update the value of the reference as the inner sequence produces new values.
I also modified to properly track the inner subscriptions and unsubscribe if the outer observable is unsubscribed.
Also modified to tear it all down if any of the streams produce an error.
Finally, I fixed some race conditions that could violate Rx Guidelines. If your inner observables are firing concurrently from different threads, you could wind up call obs.OnNext concurrently which is a big no-no. So I've gated each inner observable using the same lock to prevent that (see the Synchronize call). Note that because of this, you could probably get away with using a regular double linked list instead of the PerishableCollection because now all of the code using the collection is within a lock so you don't need the threading guarantees of the PerishableCollection.
// Acts as a reference to the current value stored in the list
private class BoxedValue<T>
{
public T Value;
public BoxedValue(T initialValue) { Value = initialValue; }
}
public static IObservable<IEnumerable<T>> MergeLatest<T>(this IObservable<IObservable<T>> source)
{
return Observable.Create<IEnumerable<T>>(obs =>
{
var collection = new PerishableCollection<BoxedValue<T>>();
var outerSubscription = new SingleAssignmentDisposable();
var subscriptions = new CompositeDisposable(outerSubscription);
var innerLock = new object();
outerSubscription.Disposable = source.Subscribe(duration =>
{
BoxedValue<T> value = null;
var lifetime = new DisposableLifetime(); // essentially a CancellationToken
var subscription = new SingleAssignmentDisposable();
subscriptions.Add(subscription);
subscription.Disposable = duration.Synchronize(innerLock)
.Subscribe(
x =>
{
if (value == null)
{
value = new BoxedValue<T>(x);
collection.Add(value, lifetime.Lifetime);
}
else
{
value.Value = x;
}
obs.OnNext(collection.CurrentItems().Select(p => p.Value.Value));
},
obs.OnError, // handle an error in the stream.
() => // on complete
{
if (value != null)
{
lifetime.Dispose(); // removes the item
obs.OnNext(collection.CurrentItems().Select(p => p.Value.Value));
subscriptions.Remove(subscription); // remove this subscription
}
}
);
});
return subscriptions;
});
}
This solution will work for one-item streams but unfortunately accumulates every item in an inner stream until it finishes.
public static IObservable<IEnumerable<T>> MergeLatest<T>(this IObservable<IObservable<T>> source)
{
return Observable.Create<IEnumerable<T>>(obs =>
{
var collection = new PerishableCollection<T>();
return source.Subscribe(duration =>
{
var lifetime = new DisposableLifetime(); // essentially a CancellationToken
duration
.Subscribe(
x => // on initial item
{
collection.Add(x, lifetime.Lifetime);
obs.OnNext(collection.CurrentItems().Select(p => p.Value));
},
() => // on complete
{
lifetime.Dispose(); // removes the item
obs.OnNext(collection.CurrentItems().Select(p => p.Value));
}
);
});
});
}
Another solution given by Dave Sexton, creator of Rxx - it uses Rxx.CombineLatest which appears to be quite similar in its implementation to Brandon's solution:
public static IObservable<IEnumerable<T>> CombineLatestEagerly<T>(this IObservable<IObservable<T>> source)
{
return source
// Reify completion to force an additional combination:
.Select(o => o.Select(v => new { Value = v, HasValue = true })
.Concat(Observable.Return(new { Value = default(T), HasValue = false })))
// Merge a completed observable to force combination with the first real inner observable:
.Merge(Observable.Return(Observable.Return(new { Value = default(T), HasValue = false })))
.CombineLatest()
// Filter out completion notifications:
.Select(l => l.Where(v => v.HasValue).Select(v => v.Value));
}

Multiple SUM using LINQ

I have a loop like the following, can I do the same using multiple SUM?
foreach (var detail in ArticleLedgerEntries.Where(pd => pd.LedgerEntryType == LedgerEntryTypeTypes.Unload &&
pd.InventoryType == InventoryTypes.Finished))
{
weight += detail.GrossWeight;
length += detail.Length;
items += detail.NrDistaff;
}
Technically speaking, what you have is probably the most efficient way to do what you are asking. However, you could create an extension method on IEnumerable<T> called Each that might make it simpler:
public static class EnumerableExtensions
{
public static void Each<T>(this IEnumerable<T> col, Action<T> itemWorker)
{
foreach (var item in col)
{
itemWorker(item);
}
}
}
And call it like so:
// Declare variables in parent scope
double weight;
double length;
int items;
ArticleLedgerEntries
.Where(
pd =>
pd.LedgerEntryType == LedgerEntryTypeTypes.Unload &&
pd.InventoryType == InventoryTypes.Finished
)
.Each(
pd =>
{
// Close around variables defined in parent scope
weight += pd.GrossWeight;
lenght += pd.Length;
items += pd.NrDistaff;
}
);
UPDATE:
Just one additional note. The above example relies on a closure. The variables weight, length, and items should be declared in a parent scope, allowing them to persist beyond each call to the itemWorker action. I've updated the example to reflect this for clarity sake.
You can call Sum three times, but it will be slower because it will make three loops.
For example:
var list = ArticleLedgerEntries.Where(pd => pd.LedgerEntryType == LedgerEntryTypeTypes.Unload
&& pd.InventoryType == InventoryTypes.Finished))
var totalWeight = list.Sum(pd => pd.GrossWeight);
var totalLength = list.Sum(pd => pd.Length);
var items = list.Sum(pd => pd.NrDistaff);
Because of delayed execution, it will also re-evaluate the Where call every time, although that's not such an issue in your case. This could be avoided by calling ToArray, but that will cause an array allocation. (And it would still run three loops)
However, unless you have a very large number of entries or are running this code in a tight loop, you don't need to worry about performance.
EDIT: If you really want to use LINQ, you could misuse Aggregate, like this:
int totalWeight, totalLength, items;
list.Aggregate((a, b) => {
weight += detail.GrossWeight;
length += detail.Length;
items += detail.NrDistaff;
return a;
});
This is phenomenally ugly code, but should perform almost as well as a straight loop.
You could also sum in the accumulator, (see example below), but this would allocate a temporary object for every item in your list, which is a dumb idea. (Anonymous types are immutable)
var totals = list.Aggregate(
new { Weight = 0, Length = 0, Items = 0},
(t, pd) => new {
Weight = t.Weight + pd.GrossWeight,
Length = t.Length + pd.Length,
Items = t.Items + pd.NrDistaff
}
);
You could also group by true - 1 (which is actually including any of the items and then have them counted or summered):
var results = from x in ArticleLedgerEntries
group x by 1
into aggregatedTable
select new
{
SumOfWeight = aggregatedTable.Sum(y => y.weight),
SumOfLength = aggregatedTable.Sum(y => y.Length),
SumOfNrDistaff = aggregatedTable.Sum(y => y.NrDistaff)
};
As far as Running time, it is almost as good as the loop (with a constant addition).
You'd be able to do this pivot-style, using the answer in this topic: Is it possible to Pivot data using LINQ?
Ok. I realize that there isn't an easy way to do this using LINQ. I'll take may foreach loop because I understood that it isn't so bad. Thanks to all of you

How can I iterate over a collection and change values with LINQ extension methods?

Lets say I have a collection of Messages which has the properties "UserID" (int) and "Unread" (bool).
How can I use LINQ extension methods to set Unread = false, for any Message in the collection in whose UserID = 5?
So, I know I can do something like:
messages.Any(m => m.UserID == 5);
But, how do I set the Unread property of each of those with an extension method as well?
Note: I know I should not do this in production code. I'm simply trying to learn some more LINQ-fu.
Actually, this is possible using only the built-in LINQ extension methods without ToList.
I believe that this will perform very similarly to a regular for loop. (I haven't checked)
Don't you dare do this in real code.
messages.Where(m => m.UserID == 5)
.Aggregate(0, (m, r) => { m.Unread = false; return r + 1; });
As an added bonus, this will return the number of users that it modified.
messages.Where(m => m.UserID == 5).ToList().ForEach(m => m.Unread = false);
Then submit the changes.
Standard LINQ extension methods doesn't include side effects aimed methods. However you can either implement it yourself or use from Reactive Extensions for .NET (Rx) like this:
messages.Where(m => m.UserID == 5).Run(m => m.Unread = false);
As there is no explicit extension method that does a ForEach, you are stuck with either using a secondary library, or writing the foreach statement on your own.
foreach (Message msg in messages.Where(m => m.UserID == 5))
{
msg.Unread = false;
}
If you really want to use a Linq statement to accomplish this, create a copy the collection using the ToList() method, accessing the ForEach() method of the List type:
messages.Where(m => m.UserID == 5).ToList().ForEach(m => m.Unread = false);
or place the side-effect in a Where() statement:
messages.Where(m =>
{
if (m.UserID == 5) { m.Unread = false; return true; }
return false;
});
In either case, I prefer to use the explicit foreach loop as it doesn't make unnecessary copies and is clearer than the Where hack.
With LINQ you can't because LINQ is a query language/extension. There is however a project called MoreLinq, which defines an extension method called ForEach which allows you to pass an action which will be performed on every element.
So, you could do with MoreLinq:
messages.Where(m => m.UserID == 5).ForEach(m => m.Unread = false);
Best Regards,
Oliver Hanappi
This answer is in the spirit of providing a solution. On could create an extension which does both the predicate (Where extension) to weed out the items and the action needed upon those items.
Below is an extension named OperateOn which is quite easy to write:
public static void OperateOn<TSource>(this List<TSource> items,
Func<TSource, bool> predicate,
Action<TSource> operation)
{
if ((items != null) && (items.Any()))
{
items.All (itm =>
{
if (predicate(itm))
operation(itm);
return true;
});
}
}
Here is it in action:
var myList = new List<Item>
{ new Item() { UserId = 5, Name = "Alpha" },
new Item() { UserId = 5, Name = "Beta", UnRead = true },
new Item() { UserId = 6, Name = "Gamma", UnRead = false }
};
myList.OperateOn(itm => itm.UserId == 5, itm => itm.UnRead = true);
Console.WriteLine (string.Join(" ",
myList.Select (itm => string.Format("({0} : {1})",
itm.Name,
itm.UnRead ))));
/* Outputs this to the screen
(Alpha : True) (Beta : True) (Gamma : False)
*/
...
public class Item
{
public bool UnRead { get; set; }
public int UserId { get; set; }
public string Name { get; set; }
}
You should be able to just do it in a Select(), remember the lambda is a shortcut for a function, so you can put as much logic in there as you want, then return the current item being enumerated. And... why exactly wouldn't you do this in production code?
messages = messages
.Select(m =>
{
if (m.UserId == 5)
m.Unread = true;
return m;
});

Categories

Resources