This question already has answers here:
C# List of objects, how do I get the sum of a property
(4 answers)
Closed 8 years ago.
How can the following Generic List be summed up by total cost? Meaning is it possible to add both costs below to get a total?
Model:
public class Product
{
public string Name {get;set;}
public int Cost {get;set;}
}
Now I want to use that model in a Generic list like this:
public void GetTotal()
{
IList<Product> listOfJediProducts = new List<Product>();
Product newProduct1 = new Product();
newProduct1.Name = "LightSaber";
newProduct1.Cost = 1500;
listOfJediProducts.Add(newProduct1);
Product newProduct2 = new Product();
newProduct2.Name = "R2RobotSpec9";
newProduct2.Cost = 5000;
listOfJediProducts.Add(newProduct2);
}
How would I return say a Total for Products in list?
listOfJediProducts.Sum(p => p.Cost);
This runs the selector lambda expression over each element in the sequence (returning Cost in this case). The Sum function is then run on the "implicitly returned" IEnumerable, which obviously calculates the sum and returns it.
It is worth noting that the above is similar to writing:
listOfJediProducts.Select(p => p.Cost).Sum();
Which may be a little more obvious (if not verbose) in understanding what my first example does.
I say "implicitly returned" because Sum only makes sense on an IEnumerable of numbers, the internal workings are probably doing something closer to this:
int total;
foreach (Product p in listOfJediProducts)
total += p.Cost;
return total;
else, using foreach loop
int total_cost = 0;
foreach (Product p in listOfJediProducts)
{
total_cost+= p.cost;
}
Related
I have class ObjectA with property called Value.
I have also class ObjectB with property called Sum.
Then I have List<ObjectA> listA.
How to return List<ObjectB> listB from C# Enumerable.Aggregate method, where property Sum of every following ObjectB is the (rising) aggregated sum of properties Value from List<ObjectA>?
EXPECTED BEHAVIOUR:
IN: List of ObjectA with following properties Value {1,2,3,4,5,6}
OUT: List of ObjectB with following properties Sum {1,3,6,10,15,21}
Short answer: Don't. Use Select or a loop instead.
Long answer:
Aggregate is intended for cases where you start with a list of values, but want to end up with a single value. You're trying to end up with another collection, with one value for each input.
That's not to say it can't be done. Just for academic purposes, let's look at some of the patterns you could use. I'm going to simplify the problem to just use integers instead of ObjectA and ObjectB.
This is probably the most "pure" approach, in the sense that the delegate you pass to Aggregate has no side-effects.
var values = new[]{1,2,3,4,5,6};
var sums = values.Aggregate(Enumerable.Empty<int>(), (previous, next) => previous.Append(previous.LastOrDefault() + next)).ToList();
However, this probably has O(n²) complexity because you're calling LastOrDefault() on IEnumerable<>s constructed by chaining Append calls together. It might be preferable to accept a little impurity by closing over a running total variable.
var values = new[]{1,2,3,4,5,6};
int runningTotal = 0;
var sums = values.Aggregate(Enumerable.Empty<int>(), (previous, next) => previous.Append(runningTotal += next)).ToList();
But if we're willing to track state that way, things could be much simpler by just using Select instead of Aggregate:
int runningTotal = 0;
var sums = values.Select(next => runningTotal += next).ToList();
And of course, purists would say that functional syntax like LINQ statements shouldn't have side-effects. It might be clearer to just build out a new list with a more imperative-style foreach loop.
var values = new[]{1,2,3,4,5,6};
var sums = new List<int>();
int runningTotal = 0;
foreach(var next in values)
{
runningTotal += next;
sums.Add(runningTotal);
}
You can do the Aggregate in the following way:
var objectBs = objectAs
.Aggregate<ObjectA, IEnumerable<ObjectB>>(
Enumerable.Empty<ObjectB>(),
(objectBs, objectA) => objectBs.Append(new ObjectB
{
Sum = (objectBs.LastOrDefault()?.Sum ?? 0) + objectA.Value
}));
But this hard to read for people (I personally do). Alternatively, write it with a for loop:
var listOfObjectBs = new List<ObjectB>
{
new ObjectB
{
Sum = objectAs.First().Value
}
};
for (var i = 1; i < objectAs.Count; i++)
{
listOfObjectBs.Add(new ObjectB
{
Sum = listOfObjectBs[i - 1].Sum + objectAs[i].Value
});
}
This question already has answers here:
LINQ: Add RowNumber Column
(9 answers)
Closed 6 years ago.
I would like to access the row number in linq query.
There are many articles on the web stating how to do this but there is a catch:
I want to resolve the enumeration "later" and I want it to assign the same ID every time.
For this reason methods such as this do not work:
public IEnumerable<MyClass> GetThings(List<object> lst)
{
int ID=0;
return from i in lst
select new MyClass(ID++, i);
}
public class MyClass
{
public MyClass(int ID, object Stuff)
{ ... }
}
...
var x = GetThings(SomeList);
(fails because each time you resolve x by iterating each item gets a different id)
Actually you can use the Select overload that pass the index too, something like this:
lst.Select((o, i) => new MyClass(i, o));
Turns out the solution to this is quite simple - grab the row number of the source collection, not the output collection.
Obviously this only works if you are not filtering etc. and the number of items in your output collection is the same as the input collection. Unless you're ok with gaps and/or duplicates
i.e.
public IEnumerable<MyClass> GetThings(List<object> lst)
{
int ID=0;
return from i in lst.Select((item,id)=>new {Item=item, ID=id})
select new MyClass(i.ID, i.Item);
}
public class MyClass
{
public MyClass(int ID, object Stuff)
{ ... }
}
...
var x = GetThings(SomeList);
now the ID's of each item in x is the same every time you iterate it
As I understand the Aggregate extension method, I should be able to use it to iterate through a collection and perform operations on the current and previous element; for example:
var totalSum = myIntCollection.Aggregate( (a,b) => a + b);
However, can (and if so how) can I use this to add class properties; for example:
totalSum = MyCollection.Aggregate((a, b) => a.MyInt + b.MyInt);
Given that MyCollection is a List<MyClass> and MyClass looks like this:
public class MyClass
{
public string Name { get; set; }
public int MyInt { get; set; }
}
When I try to compile the above statement, it tells me that it can't implicitly covert int to MyClass.
So, my question is: why is it giving this error, and is there a way around it?
You misunderstood on what Aggregate method operates. It does not "perform operations on the current and previous element".
It performs operations on an accumulator and current element.
So, in your first example var totalSum = myIntCollection.Aggregate( (a,b) => a + b);, a is not a previous element; it represents the sum of all elements that appear before current element (b). I think your misunderstanding is due to the fact that the Aggregate method in your case started by adding the first two elements.
Anyway, as #Sayse and #Jon Skeet pointed out, you're better of with using Sum in this case:
var totalSum = MyCollection.Sum(item => item.MyInt);
The way around it would be
MyCollection.Sum(a => a.MyInt)
How can one go about sharing query logic between LINQ and Rx? i.e., if I need to sometimes query against an IObservable stream and sometimes against an IEnumerable, but the exact same logic is in each, is there any way to share that logic?
Maybe an example will help. In the following Queries class, I want to combine the sequence of people and purchases to produce a "notice" string. Notice I have to duplicate the exact same logic; all that's different is that one is IEnumerable and one is IObservable. Is there any way of consolidating these two functions? I've tried using various combinations of ToObservable and ToEnumerable, but everything I've tried seems to either hang or produce no result.
(Higher-kinded question: Is this the exact thing that the idea of higher-kinded types was created to solve? i.e., would this not even be a problem in Haskell or Scala?)
static class Queries {
static IObservable<string> GetPurchaseNotices(IObservable<Person> people, IObservable<Purchase> purchases) {
return from person in people
from purchase in purchases
where person.Id == purchase.PurchaserId
select person.Name + " purchased a " + purchase.ItemName;
}
static IEnumerable<string> GetPurchaseNotices(IEnumerable<Person> people, IEnumerable<Purchase> purchases) {
return from person in people
from purchase in purchases
where person.Id == purchase.PurchaserId
select person.Name + " purchased a " + purchase.ItemName;
}
}
class Person {
public Person(int id, string name) {
Id = id;
Name = name;
}
public string Name;
public int Id;
}
class Purchase {
public Purchase(int purchaserId, string itemName) {
PurchaserId = purchaserId;
ItemName = itemName;
}
public int PurchaserId;
public string ItemName;
}
As far as I know, this is not possible in C# (or F#) directly. The problem is that while you can abstract over the generic argument T in IEnumerable<T> or IObservable<T>, you cannot abstract over the "kind" IEnumerable or IObservable.
With higher-kinded types, like those in Haskell or Scala, you could express this given a suitable interface for IEnumerble and IObservable. In Haskell, it would look something like:
getPurchases :: MonadPlus m => m Person -> m Purchaser -> m String
getPurchases people purchases = do
person <- people
purchase <- purchases
if (personId person) == (purchaserId purchase)
then return $ (name person) ++ "purchased a " ++ (itemName purchase)
else mzero
which you could then use for both IEnumerable and IObservable.
I don't know whether IObservable actually satisfies the required laws for MonadPlus however, so this is just an example.
Switching from observable to enumerable is not a good idea since the enumerable will block, so it will be less problematic the other way around. You should be able to use a single function that filters an IObservable<Person>.
Here's simple program that demonstrates the idea. Notice it uses a single method for filtering IObservable<int>. In case of IEnumerable<int>, it switches ToObservable before calling the method, and then switches back ToEnumerable after getting the result.
static void Main(string[] args)
{
var observableNums = Observable.Interval(TimeSpan.FromSeconds(1))
.Select(x => (int)x);
var observableOdds = FilterOdds(observableNums);
observableOdds.Subscribe(Console.WriteLine);
var enumerableNums = new[] { 1, 2, 3, 4, 5, 6 };
var enumerableOdds = FilterOdds(enumerableNums.ToObservable());
foreach (var i in enumerableOdds.ToEnumerable())
Console.WriteLine(i);
Console.ReadKey();
}
static IObservable<int> FilterOdds(IObservable<int> nums)
{
return nums.Where(i => i % 2 == 1);
}
This question already has answers here:
What is a Predicate Delegate and where should it be used?
(10 answers)
Closed 8 years ago.
I am very new to using predicates and just learned how to write:
Predicate<int> pre = delegate(int a){ a %2 == 0 };
What will the predicate return, and how is it useful when programming?
Predicate<T> is a functional construct providing a convenient way of basically testing if something is true of a given T object.
For example suppose I have a class:
class Person {
public string Name { get; set; }
public int Age { get; set; }
}
Now let's say I have a List<Person> people and I want to know if there's anyone named Oscar in the list.
Without using a Predicate<Person> (or Linq, or any of that fancy stuff), I could always accomplish this by doing the following:
Person oscar = null;
foreach (Person person in people) {
if (person.Name == "Oscar") {
oscar = person;
break;
}
}
if (oscar != null) {
// Oscar exists!
}
This is fine, but then let's say I want to check if there's a person named "Ruth"? Or a person whose age is 17?
Using a Predicate<Person>, I can find these things using a LOT less code:
Predicate<Person> oscarFinder = (Person p) => { return p.Name == "Oscar"; };
Predicate<Person> ruthFinder = (Person p) => { return p.Name == "Ruth"; };
Predicate<Person> seventeenYearOldFinder = (Person p) => { return p.Age == 17; };
Person oscar = people.Find(oscarFinder);
Person ruth = people.Find(ruthFinder);
Person seventeenYearOld = people.Find(seventeenYearOldFinder);
Notice I said a lot less code, not a lot faster. A common misconception developers have is that if something takes one line, it must perform better than something that takes ten lines. But behind the scenes, the Find method, which takes a Predicate<T>, is just enumerating after all. The same is true for a lot of Linq's functionality.
So let's take a look at the specific code in your question:
Predicate<int> pre = delegate(int a){ return a % 2 == 0; };
Here we have a Predicate<int> pre that takes an int a and returns a % 2 == 0. This is essentially testing for an even number. What that means is:
pre(1) == false;
pre(2) == true;
And so on. This also means, if you have a List<int> ints and you want to find the first even number, you can just do this:
int firstEven = ints.Find(pre);
Of course, as with any other type that you can use in code, it's a good idea to give your variables descriptive names; so I would advise changing the above pre to something like evenFinder or isEven -- something along those lines. Then the above code is a lot clearer:
int firstEven = ints.Find(evenFinder);
The Predicate will always return a boolean, by definition.
Predicate<T> is basically identical to Func<T,bool>.
Predicates are very useful in programming. They are often used to allow you to provide logic at runtime, that can be as simple or as complicated as necessary.
For example, WPF uses a Predicate<T> as input for Filtering of a ListView's ICollectionView. This lets you write logic that can return a boolean determining whether a specific element should be included in the final view. The logic can be very simple (just return a boolean on the object) or very complex, all up to you.
The following code can help you to understand some real world use of predicates (Combined with named iterators).
namespace Predicate
{
class Person
{
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
foreach (Person person in OlderThan(18))
{
Console.WriteLine(person.Age);
}
}
static IEnumerable<Person> OlderThan(int age)
{
Predicate<Person> isOld = x => x.Age > age;
Person[] persons = { new Person { Age = 10 }, new Person { Age = 20 }, new Person { Age = 19 } };
foreach (Person person in persons)
if (isOld(person)) yield return person;
}
}
}
In C# Predicates are simply delegates that return booleans. They're useful (in my experience) when you're searching through a collection of objects and want something specific.
I've recently run into them in using 3rd party web controls (like treeviews) so when I need to find a node within a tree, I use the .Find() method and pass a predicate that will return the specific node I'm looking for. In your example, if 'a' mod 2 is 0, the delegate will return true. Granted, when I'm looking for a node in a treeview, I compare it's name, text and value properties for a match. When the delegate finds a match, it returns the specific node I was looking for.