Расчет максимальных и минимальных значений в массиве - PullRequest
3 голосов
/ 08 октября 2009

У меня есть массив целых чисел, и мне нужно найти позицию в массиве максимального числа вместе с минимумом. У меня это работает, но это не очень хороший способ сделать это. Кто-нибудь может предложить лучший способ добиться того, что у меня есть?

Вот мой код:

int[] usageHours = { 3, 3, 5, 4, 0, 0, 2, 2, 4, 25, 158, 320, 212, 356, 401, 460, 480, 403, 298, 213, 102, 87, 34, 45 };
double myAverage = usageHours.Average();
int runningTotal = 0;
int runningMaxPosition = 0;

for (int i = 0; i < usageHours.Length; i++)
{
    if (usageHours[i] > runningTotal)
    {
        runningMaxPosition = i;
        runningTotal = usageHours[i];
    }
}

txtmax.Text = Convert.ToString(runningMaxPosition)+" With: "+Convert.ToString(runningTotal)+" Users";
txtAv.Text = Convert.ToString(myAverage);

Ответы [ 7 ]

7 голосов
/ 08 октября 2009

Этот код в основном в порядке. Я бы посоветовал немного изменить имена переменных, но это все. Вы можете отработать минимум в одном цикле. Я слегка изменил условия «если», чтобы они всегда выбирали хотя бы один элемент (даже если все значения, скажем, int.MinValue). Есть и другие способы решения этой проблемы, но это один из примеров. Если у вас есть пустой массив, вы получите max = min = 0 и оба индекса = -1.

int currentMax = 0;
int currentMaxIndex = -1;
int currentMin = 0;
int currentMinIndex = -1;

for (int i = 0; i < usageHours.Length; i++)
{
    if (currentMaxIndex == -1 || usageHours[i] > currentMax)
    {
        currentMaxIndex = i;
        currentMax = usageHours[i];
    }
    if (currentMinIndex == -1 || usageHours[i] < currentMin)
    {
        currentMinIndex = i;
        currentMin = usageHours[i];
    }
}

Вот альтернатива, использующая типы значений, допускающие значение nullable , для представления ответов «не было значений»:

int currentMax? = null;
int currentMaxIndex? = null;
int currentMin? = null;
int currentMinIndex? = null;

for (int i = 0; i < usageHours.Length; i++)
{
    if (currentMax == null || usageHours[i] > currentMax.Value)
    {
        currentMax = i;
        currentMax = usageHours[i];
    }
    if (currentMin == null || usageHours[i] < currentMin.Value)
    {
        currentMinIndex = i;
        currentMin = usageHours[i];
    }
}

Не беспокойтесь, если вы еще не сталкивались с типами значений, которые можно обнулять ...

2 голосов
/ 08 октября 2009

Код выглядит нормально для поиска максимального значения. Если вы используете C # 3 или более позднюю версию, вы можете использовать методы расширения LINQ (есть методы Min, Max и Average, а на List есть также метод FindIndex, среди прочих), но У меня складывается впечатление, что вы изучаете программирование, и тогда иногда полезно реализовать вещи, которые могут быть встроены в структуру, просто для учебной ценности.

1 голос
/ 14 июля 2010

Я просто хотел предоставить однострочное решение вопроса (для полноты). В оригинальном вопросе ОП он просит только индекс максимума и индекс минимума.

Давайте придерживаться этого вопроса. Это наиболее интересный вопрос, потому что для поиска максимального значения мы можем просто использовать метод Enumerable.Max LINQ. То же самое касается Min и Average.

Давайте предоставим только индекс max, индекс min можно получить с помощью аналогичного кода.

int indexOfMax = Enumerable.Range(0, usageHours.Length).Aggregate(
    (indexOfMax, i) => (usageHours[i] > usageHours[indexOfMax] ? i : indexOfMax)
);

Делегат внутри скобок Агрегата выполняется для каждого индекса массива. Он получает в качестве параметров «индекс максимального значения, найденного на данный момент», и текущий индекс. Возвращает «индекс максимального значения, найденного на данный момент». Очевидно, что в каждой итерации «индекс максимального значения, найденного на данный момент» будет изменяться на текущий индекс только в том случае, если соответствующий элемент массива больше предыдущего максимума.

0 голосов
/ 08 октября 2009

Как уже упоминалось в комментарии к ответу Джона, решение Джона действительно является лучшим, самым прямым и быстрым способом сделать это.

Если, однако, вы хотели использовать решение Игоря, вот его остальная часть (чтобы получить фактические позиции и значения):

int maxValue = Enumerable.Range(0, usageHours.Length).Max(i => usageHours[i]);
int maxPosition = Array.FindIndex(usageHours, i => i == maxValue);
int minValue = Enumerable.Range(0, usageHours.Length).Min(i => usageHours[i]);
int minPosition = Array.FindIndex(usageHours, i => i == minValue);
0 голосов
/ 08 октября 2009

Ваш код неплох, но он не будет работать, если все значения меньше нуля.

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

int getArrayMaxPosition (double[] theArray) 
{    
    double maxVal = theArray[0];
    int ret = 0;
    int currentIndex = 0;

    foreach (double aValue in theArray) 
    {
        if (aValue > maxVal)
        {
             ret = currentIndex;
             maxVal = avalue;
        }
        currentIndex++;
    }

    return ret;
 }
0 голосов
/ 08 октября 2009

Как насчет этого:

double average = usageHours.Average();
int maxPosition = Enumerable.Range(0, usageHours.Length).Max(i => usageHours[i]);
int minPosition = Enumerable.Range(0, usageHours.Length).Min(i => usageHours[i]);
0 голосов
/ 08 октября 2009

поцарапайте код linq, он работает не так, как вы хотели

Вы могли бы сделать свой код немного более кратким

for (int i = 0; i < usageHours.Length; i++)
{
    if (usageHours[i] > usageHours[runningMaxPosition])
        runningMaxPosition = i;
}

все, что он делает по-другому, это исключает временную переменную runningTotal.

...