Создать функцию Microsoft Excel SumIf в списке

#c# #generics

#c# #общие

Вопрос:

Мне нужно написать общий метод расширения List<T> , который условно учитывает несколько Textbox значений (10 из них), чтобы увидеть, не превышает ли каждое из них 25, а затем Sum другой набор Textbox значений, если условие выполнено.

то же, SUMIF что и в Microsoft Excel, где (диапазон (массив текстового поля1), критерии (=<25), сумма диапазона (массив текстового поля2). =SUMIF(F7,»<=25″, I10) SUMIF(L13, «<=25»,L20)

Я использовал следующий код из другого потока, я просто не знаю, как это реализовать одним нажатием кнопки.

 public static double SumIf<T>(
      IEnumerable<T> source,
      Func<T, double > textSelector,
      Func<T, double> valueSelector)
{
    return source.Where(x => textSelector(x) <= 25.5).Sum(valueSelector);
}
  

Комментарии:

1. Немного неясно, о чем вы спрашиваете (по крайней мере, для меня) в отношении 2 списков

2. Что вы имеете в виду? Конечно, вы бы вызвали SumIf из обработчика нажатия кнопки?

3. Это приложение WPF?

4. Есть ли какие-либо случаи, когда textSelector valueSelector ожидается, что и будут разными? Если нет, вы source.Select(textSelector).Where(x => x <= 25.5).Sum(); также должны сделать, для чего targetText используется?

5. На самом деле неясно, в чем заключается ваша проблема. Добавьте кнопку, добавьте событие при «щелчке», напишите код для передачи значений из ваших текстовых полей в этот метод и т.д. Обратите внимание, что мое предложение все еще очень общее, потому что мы не знаем, какую среду пользовательского интерфейса вы используете (WinForms, WPF, WebForms, MVC и т. Д.) Или Где проблема в реализации.

Ответ №1:

Предлагаемый SumIf вами метод немного неудобен для ваших целей.

Давайте предположим, что вам удалось определить два массива текстовых полей — первый набор, который вы проверяете, если значение меньше 25, а другой, который вы хотите суммировать:

 TextBox[] firstTextBoxes = ...;
TextBox[] otherTextBoxes = ...;
  

Теперь, чтобы я мог использовать ваш существующий SumIf метод, мне нужно вызвать его следующим образом:

 double result =
    Ex.SumIf(
        firstTextBoxes.Zip(otherTextBoxes, (first, other) => new { first, other }),
        x => double.Parse(x.first.Text),
        x => double.Parse(x.other.Text));
  

Zip Пары текстовых полей, а затем вы можете вызвать SumIf парный список.

Способ написания кода просто скрывает часть логики внутри SumIf , и остается очень мало интересного кода, чтобы рассказать вам, что происходит.

Ваш код трудно понять.

Один из подходов заключается в том, чтобы изменить SumIf SumOtherIfFirstLessThanEqual25 его следующим образом:

 public static double SumOtherIfFirstLessThanEqual25(IEnumerable<(TextBox first, TextBox other)> source)
{
    return source.Where(x => double.Parse(x.first.Text) <= 25.0).Sum(x => double.Parse(x.other.Text));
}
  

Теперь вы можете написать:

 double result =
    Ex.SumOtherIfFirstLessThanEqual25(
        firstTextBoxes.Zip(otherTextBoxes, (first, other) => (first, other)));
  

Теперь, если вы перейдете SumOtherIfFirstLessThanEqual25 к методу расширения:

 public static class Ex
{
    public static double SumOtherIfFirstLessThanEqual25(this IEnumerable<(TextBox first, TextBox other)> source)
    {
        return source.Where(x => double.Parse(x.first.Text) <= 25.0).Sum(x => double.Parse(x.other.Text));
    }
}
  

…вы можете написать это:

 double result =
    firstTextBoxes
        .Zip(otherTextBoxes, (first, other) => (first, other))
        .SumOtherIfFirstLessThanEqual25();
  

Это читаемо, и вы можете понять, что происходит.

Однако лучше придерживаться более стандартного подхода.

Вы могли бы написать свой SumIf метод следующим образом:

 public static class Ex
{
    public static double SumIf<T>(this IEnumerable<T> source,
        Func<T, bool> filter,
        Func<T, double> selector)
    {
        return source.Where(x => filter(x)).Sum(selector);
    }
}
  

Теперь вы можете написать это:

 double result =
    Ex1.SumIf(
        firstTextBoxes.Zip(otherTextBoxes, (tb, otb) => new { tb, otb }),
        x => double.Parse(x.tb.Text) <= 25.0,
        x => double.Parse(x.otb.Text));
  

Это лучше и, как правило, содержит всю логику в нужном месте. Но это все равно можно улучшить, если вы полностью избавитесь от SumIf метода.

Попробуйте это:

 double result =
    firstTextBoxes
        .Zip(otherTextBoxes, (tb, otb) => new { tb, otb })
        .Where(x => double.Parse(x.tb.Text) <= 25.0)
        .Sum(x => double.Parse(x.otb.Text));
  

Это имеет все те же функциональные возможности, но логика построена с использованием стандартных операторов LINQ, и она четко пошаговая и легко читается.

Теперь вам просто нужно написать это:

 private void button1_Click(object sender, EventArgs e)
{
    TextBox[] firstTextBoxes = /* populate your first array here */;
    TextBox[] otherTextBoxes = /* populate your other array here */;

    double result =
        firstTextBoxes
            .Zip(otherTextBoxes, (tb, otb) => new { tb, otb })
            .Where(x => double.Parse(x.tb.Text) <= 25.0)
            .Sum(x => double.Parse(x.otb.Text));

    //do something with `result` here
}
  

Комментарии:

1. это именно то, чего я ожидал в результате, теперь это более понятно, большое спасибо за введение другого метода и извините за неясность