Поиск, сколько раз экземпляр встречается в списке - PullRequest
2 голосов
/ 27 июня 2019

У меня есть список, и моя цель - определить, сколько раз значения в этом списке превышают определенное значение.

Например, если мой список: List = {0, 0, 3, 3, 4, 0, 4, 4, 4} Я хотел бы знать, что было два случая, когда мои значения в списке были больше 2 и оставались выше 2. Таким образом, в этом случае было 2 случая, так как он опустился ниже 2 водна точка и снова поднялся над ней.

    private void Report_GeneratorButton_Click(object sender, EventArgs e)
    {
        //Lists
        var current = _CanDataGraph._DataPoints[CanDataGraph.CurveTag.Current].ToList();
        var SOC = _CanDataGraph._DataPoints[CanDataGraph.CurveTag.Soc].ToList();
        var highcell = _CanDataGraph._DataPoints[CanDataGraph.CurveTag.HighestCell].ToList();
        var lowcell = _CanDataGraph._DataPoints[CanDataGraph.CurveTag.LowestCell].ToList();

        //Seperates current list into charging, discharging, and idle
        List<double> charging = current.FindAll(i => i > 2);
        List<double> discharging = current.FindAll(i => i < -2);
        List<double> idle = current.FindAll(i => i < 2 && i > -2);

        //High cell
        List<double> overcharged = highcell.FindAll(i => i > 3.65);
        int ov = overcharged.Count;

        if (ov > 1)
        {
            Console.WriteLine("This Battery has gone over Voltage!");
        }

        else
        {
            Console.WriteLine("This battery has never been over Voltage.");
        }

        //Low cell
        List<double> overdischarged = lowcell.FindAll(i => i > 3.65);
        int lv = overdischarged.Count;

        if (lv > 1)
        {
            Console.WriteLine("This Battery has been overdischarged!");
        }

        else
        {
            Console.WriteLine("This battery has never been overdischarged.");
        }


        //Each value is 1 second
        int chargetime = charging.Count;
        int dischargetime = discharging.Count;
        int idletime = idle.Count;


        Console.WriteLine("Charge time: " + chargetime + "s" + "\n" + "Discharge time: " + dischargetime + "s" + "\n" + "Idle time: " + idletime);

    }

Мой текущий код и вывод:

    This battery has never been over Voltage.
    This battery has never been overdischarged.
    Charge time: 271s
    Discharge time: 0s
    Idle time: 68

Ответы [ 6 ]

4 голосов
/ 27 июня 2019

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

Вот более простая проблема: учитывая последовательность T, верните мне последовательность T с удаленными «удвоенными» элементами:

public static IEnumerable<T> RemoveDoubles<T>(
  this IEnumerable<T> items) 
{
  T previous = default(T);
  bool first = true;
  foreach(T item in items)
  {
    if (first || !item.Equals(previous)) yield return item;
    previous = item;
    first = false;
  }
}

Отлично. Как это полезно? Потому что решение вашей проблемы сейчас:

int count = myList.Select(x => x > 2).RemoveDoubles().Count(x => x);

Следуйте.

Если у вас myList как {0, 0, 3, 3, 4, 0, 4, 4, 4}, то результат Select будет {false, false, true, true, true, false, true, true, true}.

Результат RemoveDoubles равен {false, true, false, true}.

Результат Count равен 2, что является желаемым результатом.

Старайтесь использовать готовые детали, когда можете. Если вы не можете, попробуйте решить простую общую задачу , которая даст вам то, что вам нужно; теперь у вас есть инструмент, который вы можете использовать для других задач, требующих удаления дубликатов в последовательности.

2 голосов
/ 27 июня 2019

Это решение должно достичь желаемого результата.

    List<int> lsNums = new List<int>() {0, 0, 3, 3, 4, 0, 4, 4, 4} ;
    public void MainFoo(){
        int iChange = GetCritcalChangeNum(lsNums, 2);
        Console.WriteLine("Critical change = %d", iChange);
    }
    public int GetCritcalChangeNum(List<int> lisNum, int iCriticalThreshold) { 
        int iCriticalChange = 0;
        int iPrev = 0;
        lisNum.ForEach( (int ele) => { 
            if(iPrev <= iCriticalThreshold && ele > iCriticalThreshold){
                iCriticalChange++;
            }
            iPrev = ele;
        });

        return iCriticalChange;
    }
1 голос
/ 27 июня 2019

Вы можете создать метод расширения, как показано ниже.

public static class ListExtensions
{
    public static int InstanceCount(this List<double> list, Predicate<double> predicate)
    {
        int instanceCount = 0;
        bool instanceOccurring = false;

        foreach (var item in list)
        {
            if (predicate(item))
            {
                if (!instanceOccurring)
                {
                    instanceCount++;
                    instanceOccurring = true;
                }
            }
            else
            {
                instanceOccurring = false;
            }
        }

        return instanceCount;
    }
}

И использовать только что созданный метод, как этот

current.InstanceCount(p => p > 2)
0 голосов
/ 27 июня 2019

Другой способ сделать это с помощью System.Linq состоит в том, чтобы пройти по списку, выбрав и сам item, и его index, и вернуть true для каждого элемента, где элемент больше value, ипредыдущий элемент меньше или равен value, а затем выберите число true результатов.Конечно, для индекса 0 существует особый случай, когда мы не проверяем предыдущий элемент:

public static int GetSpikeCount(List<int> items, int threshold)
{
    return items?
        .Select((item, index) =>
            index == 0
                ? item > threshold
                : item > threshold && items[index - 1] <= threshold)
        .Count(x => x == true)  // '== true' is here for readability, but it's not necessary
           ?? 0;  // return '0' if 'items' is null
}   

Пример использования:

private static void Main()
{
    var myList = new List<int> {0, 0, 3, 3, 4, 0, 4, 4, 4};
    var count = GetSpikeCount(myList, 2);
    // count == 2
}
0 голосов
/ 27 июня 2019

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

int [] array = new int [9]{0, 0, 3, 1, 4, 0, 4, 4, 4};
List<int> values = array.ToList();

int overCount = 0;
bool currentlyOver2 = false;

for (int i = 0; i < values.Count; i++) 
{
    if (values[i] > 2)
    {
        if (!currentlyOver2)
            overCount++;

        currentlyOver2 = true;
    }
    else
        currentlyOver2 = false;
}
0 голосов
/ 27 июня 2019
public static int CountOverLimit(IEnumerable<double> items, double limit)
{
    int overLimitCount = 0;
    bool isOverLimit = false;

    foreach (double item in items)
    {
        if (item > limit)
        {
            if (!isOverLimit)
            {
                overLimitCount++;
                isOverLimit = true;
            }
        }
        else if (isOverLimit)
        {
            isOverLimit = false;
        }
    }
    return overLimitCount;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...