2

Hi all I'm new to C#.

I try to return a result "totalAmount" from my method called "GetAllKschl". In this method I returned a list with "KSCHL, KSCHLData, price, pieces und totalPrice".

So in my new method I need the total amount of all "totalPrice" together.

first method:

public List<Result> GetAllKschl(string fileNameResult, string fileNameData)
{
    List<Result> listResult = new List<Result>();
    docResult.Load(fileNameResult);
    docData.Load(fileNameData);

    var resultList = docResult.SelectNodes("//root/CalculationLogCompact/CalculationLogRowCompact");

    foreach (XmlNode nextText in resultList)
    {
        XmlNode KSCHL = nextText.SelectSingleNode("KSCHL");
        string nextKschl = KSCHL.InnerText;

        // ... and so on...

        if (pieces > 0 && totalPrice > 0)
        {
            listResult.Add(new Result(nextKschl, nextKSCHLData, nextEinzelpreis, pieces, totalPrice));
        }
    }
    return listResult;
}

second method: (don't know exactly what to do)

public decimal GetTotalAmount(string amount, string totalAmount)
{
    string total = GetAllKschl(amount, totalAmount); // ??

    return total;
}            

So here I want to have just the TotalAmount (every totalPrice from GetAllKschl) und not the whole list from GetAllKschl. How do I do this?

here my class result:

public class Result
{
    public string KSCHL { get; set; }
    public string Info { get; set; }
    public int individualPrice { get; set; }
    public int Pieces { get; set; }
    public int TotalCosts { get; set; }

    public Result(string kschl, string info, int individualPrice, int pieces, int totalCosts)
    {
        KSCHL = kschl;
        Info = info;
        IndividualPrice = individualPrice;
        Pieces = pieces;
        TotalCosts = totalCosts;
    }
}
  • 1
    Can You show the class `Result`? – Tatranskymedved Feb 13 '18 at 08:53
  • string total = GetAllKschl(amount, totalAmount).Count, that is if the result is actually a list and not a modal of some sort. – uk2k05 Feb 13 '18 at 08:55
  • The parameters to `GetAllKschl` are strings but they seem to be pointing to file names. – Martin Zikmund Feb 13 '18 at 08:56
  • @Tatranskymedved I edited my question with it. –  Feb 13 '18 at 08:56
  • Unrelated: I recommend to use english variable names. Especially in cases like this, where you seek support in an international forum that will come in handy. Second: I suggest reconsidering the choice of int for amounts, although it is better than double. See https://stackoverflow.com/a/693376/982149 and https://stackoverflow.com/a/3730040/982149 – Fildor Feb 13 '18 at 08:58

3 Answers3

3

You can use LINQ extension method Sum to do so:

decimal total = GetAllKschl( amount, totalAmount ).Sum( result => result.Gesamtpreis );

I assume that the TotalPrice is the name of the property for price in the Result class.

The Sum extension method iterates over all items in the returned collection and sums up the prices.

You could rewrite this without LINQ like this:

var list = GetAllKschl( amount, totalAmount );
decimal total = 0;
foreach ( var item in list )
{
   total += item.Gesamtpreis;
}

As a suggestion, I would recommend making clearer variable naming conventions and do not mix variable names from different languages (English and German).

Also it is quite unusual you used decimal for the total price while Result class uses int. Maybe result should have decimals as well? It seems fitting for a price property.

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
  • and is it right to write the method with `string amount, string totalAmount` ? Or do I need the decimal here as well? –  Feb 13 '18 at 09:00
  • 1
    As long as the `amount` and `totalAmount` variables contain a file name, it should be ok. But they should then be named differently like `amountFileName` and `totalAmountFileName`, to make it clear what they represent – Martin Zikmund Feb 13 '18 at 09:01
  • yeah, it should be the same files as in the first method (fileNameResult, fileNameData). So do I have to Load those files in this method as well? –  Feb 13 '18 at 09:11
  • How do you mean load in this method as well? You call the method to get the results, isn't that correct? The files will be loaded inside and will return the data as list of `Result` instances. The question is how are you calling the `GetTotalAmount` method? – Martin Zikmund Feb 13 '18 at 09:13
  • Yeah thats correct. In the first method the files will be loaded and return a list with all the things I need. And then in the second I only need the TotalPrice. So what do you mean with how do I calling the method? Is it not right? –  Feb 13 '18 at 09:24
  • No, it is right, it makes sense to call it there, the method is not called twice, only once on that one location (definition of the method does not "call it"). But the variable names should indicate what is passed in are file names. – Martin Zikmund Feb 13 '18 at 11:07
2

The best would be probably using LINQ:

public decimal GetTotalAmount(string amount, string totalAmount)
{
    var total = GetAllKschl(amount, totalAmount).Sum(result => result.Gesamtpreis);

    return total;
} 

I'm assuming that Your result are in the property called Gesamtpreis and is of any numeric type.


EDIT:

Based on the comments I decided to put there a bit more description about LINQ extension methods and lambda method. LINQ methods allows You to use a query language similar to SQL. It works with Collection of elements (e.g. List of Result - List<Result>). On this collection You will call these methods and they will provide You some kind of result, sometimes just number (Aggregate functions like Min,Max,Sum,..) or they will do some other actions returning object or another collection (First,Last, ToList, ToDictionary).

In our care we will have a List with objects:

public class Product
{
    public string Name { get; set; }
    public int Price { get; set; }
}

List<Product> productList = new List<Product>();
productList.Add(new Product() { Name = "Car", Price = 140000 });
productList.Add(new Product() { Name = "SSD Disc", Price = 2000 });
productList.Add(new Product() { Name = "Bananan", Price = 7 });

Having those, for normal SUM You would go with:

int result = 0;
foreach(var nProduct in productList)
    result += nProduct.Price;
Console.WriteLine(result);

This is kind of short code, but it can be pretty much simplified without using variable (for intermediate results) and foreach cycle. (Actually the foreach cycle will be used but we won't need to handle/write it.) LINQ example:

var result = productList.Sum(nProduct => nProduct.Price);

Now this code is much shorter, but we have to split it into several parts to understand what actually happened:

// Saving result to variable (as anytime before)
// Note that I have changed "int" to "var", which simplifies the code,
// as You don't have to take care of "what type will the result be"
// usage is really common with LINQ also
var result = 

// calling method Sum() on the productList
productList.Sum()

// Sum will take each object in the collection and put it as a parameter called "nProduct"
// now the "=>" is something called Lambda syntax,
// that allows take paremeters from the left side and use them in code on the right side.
// left side is instance of "Product" class named as "nProduct"
Sum(nProduct => ... )

// ... is replaced with "nProduct.Price",
// which is selector that tells "make the sum of property "Price"
Sum(nProduct => nProduct.Price)

// In similar manner works other aggregate functions
var max = productList.Max(prod => prod.Price);
var min = productList.Min(prod => prod.Price);
var avg = productList.Average(prod => prod.Price);
Tatranskymedved
  • 4,194
  • 3
  • 21
  • 47
  • yeah, the `Geamtpreis` is the `TotalPrice` in my class Result. I need to write `Result result = new Result();`? and then all the parameters in the `new Result(...)` at the beginning? –  Feb 13 '18 at 09:14
  • The LINQ syntax `Sum(result => /* some code here */ )`: there is a special method called `Sum` that takes 1 parameter (named `result` in our case) and will perform the query on the right side of `=>`. With different names: By writting `myList.Sum(a => a.Price)` we will make a summary of all `Price` in `myList`. Please click on the "LINQ" in my answer to see more details. – Tatranskymedved Feb 13 '18 at 09:19
  • ahh I understand. Sorry I'm not used to LINQ, it's quit confusing, haha :) But thank you! –  Feb 13 '18 at 09:25
  • 1
    @Ronja It is LINQ extension methods combined with Lambda syntax (2 separate things), I started using that a year ago and I highly recommend to learn it. It really simplifies the code and resolve lot of issue in few lines. – Tatranskymedved Feb 13 '18 at 09:27
  • But it really _can_ be highly confusing to devs unfamiliar with both concepts @Tatranskymedved and I tend to spend some extra time on commenting them really carefully. – Fildor Feb 13 '18 at 09:34
  • 1
    @Fildor -> I agree, I will put there a bit more description for the LINQ. However the other answer provide information "how to" w/o LINQ. – Tatranskymedved Feb 13 '18 at 09:41
  • @Fildor : Added now, however I think I went a bit off with answering the question. – Tatranskymedved Feb 13 '18 at 10:00
  • @Tatranskymedved oh wow, thank you for the good and detailed explanation! –  Feb 13 '18 at 10:50
0
//In this method you are returning a List
public List<Result> GetAllKschl(string fileNameResult, string fileNameData)
{
    List<Result> listResult = new List<Result>();
    docResult.Load(fileNameResult);
    docData.Load(fileNameData);

    var resultList = docResult.SelectNodes("//root/CalculationLogCompact/CalculationLogRowCompact");

    foreach (XmlNode nextText in resultList)
    {
        XmlNode KSCHL = nextText.SelectSingleNode("KSCHL");
        string nextKschl = KSCHL.InnerText;

        // ... and so on...

        if (pieces > 0 && totalPrice > 0)
        {
            listResult.Add(new Result(nextKschl, nextKSCHLData, nextEinzelpreis, pieces, totalPrice));
        }
    }

    return listResult;
}


//On the second method you returning a decimal and expecting a string    
public decimal GetTotalAmount(string amount, string totalAmount)
{
    string total = GetAllKschl(amount, totalAmount); // ??

    return total;
}   

It would be best to change the second method as:

decimal total = GetAllKschl(amount, totalAmount).Sum(result => result.Gesamtpreis);

Add linq in the return.

Tatranskymedved
  • 4,194
  • 3
  • 21
  • 47
befree2j
  • 361
  • 5
  • 11