在每个索引处对嵌套列表中的值求和

时间:2014-10-27 05:33:00

标签: c# linq list nested

我有一个名为_DataCollection的List<List<string>>,其中每个嵌套列表都有相同数量的值。尽管是所有字符串,但嵌套列表中的值将是由字母数字字符,空字符串或货币值组成的字符串。例如

_DataCollection[0] = {"tom", "abc", "$525.34", "$123"}
_DataCollection[1] = {"dick", "xyz", "$100", "$234"}
_DataCollection[2] = {"harry", "", "$250.01", "$40"}
_DataCollection[2] = {"bob", "", "$250.01", ""}

我需要做的是想出一种方法来对所有嵌套列表中每个索引的所有值求和,并将其添加到列表中:

newSumList[0] = "N/A" since "tom" + "dick" + "harry" + "bob" can't be aggregated.
newSumList[1] = "N/A" since "abc" + "xyz" + "" + "" can't be aggregated.
newSumList[2] = "1125.36"
newSumList[3] = "397" even though the last value of the last nested list is "".

基本上,每个索引的嵌套列表中的所有数值总和。

我能想到的唯一方法是迭代这些并保持运行总计,但我想知道我是否可以使用LINQ或其他方法来做。

6 个答案:

答案 0 :(得分:9)

试试这个: -

decimal _temp =0;
int ListLength = _DataCollection.First().Count();
            var query = _DataCollection.SelectMany(x => x).
                                       Select((v, i) => new { Val = v, Index = i % ListLength })
                                       .GroupBy(x => x.Index)
                                       .Select(z => z.Sum(y => decimal.TryParse(y.Val,out _temp) ? _temp : 0));

工作Fiddle

答案 1 :(得分:4)

你走了。

var list = new List<List<string>>
{
    new List<string> {"tom", "abc", "$525.34", "$123"},
    new List<string> {"dick", "xyz", "$100", "$234"},
    new List<string> {"harry", "", "$250.01", "$40"},
    new List<string> {"bob", "", "$250.01", ""}
};

decimal num;
var itemsPerLine = list[0].Count; // 4
var res = list.SelectMany(line => line);
              .Select((s, i) => new { Text = s, Index = i })
              .GroupBy(i => i.Index % itemsPerLine) // transformed matrix here
              .Select(g => g.Sum(i => 
                   decimal.TryParse(i.Text, NumberStyles.AllowCurrencySymbol | 
                                            NumberStyles.AllowDecimalPoint, 
                                            new CultureInfo("en-US"), out num) 
                                            ? num : 0));

当然,您可以通过更改NumberStyles标志和文化信息来指定应识别为数字的内容。

答案 2 :(得分:4)

或者,对于不需要使用GroupBy重新排列序列的其他方法:

        var culture = new CultureInfo("en-US");
        List<string> sums =
            _DataCollection.Count == 0
            ? new List<string>()
            : Enumerable.Range(0, _DataCollection.First().Count)
            .Select(i => _DataCollection.Select(list => list[i])
                       .Select(s => { decimal val; return string.IsNullOrEmpty(s) ? (decimal?)0 : decimal.TryParse(s, NumberStyles.Currency, culture, out val) ? (decimal?)val : (decimal?)null; })
                       .Aggregate((decimal?)0, (sum, val) => sum + val))
            .Select(sum => sum.HasValue ? sum.Value.ToString(culture) : "N/A")
            .ToList();

答案 3 :(得分:1)

List<List<string>> _DataCollection=new List<List<string>>();
            _DataCollection.Add( new List<string> {"tom", "abc", "$525.34", "$123"});

            _DataCollection.Add( new List<string> {"dick", "xyz", "$100", "$234"});
            _DataCollection.Add( new List<string> {"harry", "", "$250.01", "$40"});
            _DataCollection.Add( new List<string> {"bob", "", "$250.01", ""});

            List<string> newSumList = new List<string>();

            for (int i = 0; i < _DataCollection.Count; i++)
            {
                decimal Sum = 0;
                string CurrentSumList;
                string Comment;
                decimal amount = 0;
                for (int j = 0; j < _DataCollection.Count; j++)
                {
                    bool IsDecimalAmount=decimal.TryParse( _DataCollection[j][i].Replace('$','0'),out amount);
                    if (IsDecimalAmount)
                    {

                        Sum += amount;
                    }
                    else
                    {
                        Comment = "String";

                    }
                }
                CurrentSumList = Sum.ToString();
                newSumList.Add(CurrentSumList);
            }

我已经实现了这个&amp;它给了我结果。

答案 4 :(得分:1)

// Replace $value with value and remove all non-value strings
var dollars = _DataCollection
    .Select(l => l.Select(str => str.Contains('$') ? str.Split('$')[1] : string.Empty));

var newSumList = new List<double>();

// Add all values in a new list
for (int i = 0; i < _DataCollection[0].Count; i++)
{
    double toAdd = 0;
    foreach (var entry in dollars)
    {
        // If entry is a value, parse it, 0 otherwise
        var value = entry.ElementAt(i) != string.Empty ? double.Parse(entry.ElementAt(i)) : 0;
        toAdd = toAdd + value;
    }
    newSumList.Add(toAdd);
}
newSumList.ForEach(Console.WriteLine);

答案 5 :(得分:0)

无需多次迭代并支持空源列表

var list = new List<string[]>
{
    new [] {"tom", "abc", "$525.34", "$123"},
    new [] {"dick", "xyz", "$100", "$234"},
    new [] {"harry", "", "$250.01", "$40"},
    new [] {"bob", "", "$250.01", ""}
};
var cutlure = new CultureInfo("en-US");
var result = list.Aggregate((decimal[])null, (sums, strings) =>
    {
        if (sums == null)
            sums = Enumerable.Repeat(decimal.MinValue, strings.Length).ToArray();
        for (int i = 0; i < strings.Length; i++)
        {
            decimal value;
            if (decimal.TryParse(strings[i], NumberStyles.Currency, cutlure, out value))
                sums[i] = (sums[i] == decimal.MinValue) ? value : sums[i] + value;
        }
        return sums;
    },
    sums => sums.Select(sum => (sum == decimal.MinValue) ? "N/A" : sum.ToString()).ToArray());