C # tìm chỉ số và giá trị mảng cao nhất


92

Vì vậy, tôi có một mảng số chưa được sắp xếp int[] anArray = { 1, 5, 2, 7 };và tôi cần lấy cả giá trị và chỉ số của giá trị lớn nhất trong mảng sẽ là 7 và 3, tôi sẽ làm như thế nào?


Cho đến nay tôi đã cố gắng sử dụng phương thức Max () và sau đó sử dụng phương pháp tìm kiếm nhị phân để lấy chỉ mục của giá trị tối đa đó nhưng điều này không hoạt động trừ khi mảng được sắp xếp nên tôi không thể sử dụng nó, khi tôi thử nó cho tôi số âm
Edmund Rojas

@EdmundRojas Bạn không cần phải sử dụng tìm kiếm nhị phân. Tìm kiếm tuyến tính đơn giản hoạt động tốt cho các danh sách không được sắp xếp.
millimoose 7/12/12

Câu trả lời:


144

Đây không phải là cách quyến rũ nhất nhưng hiệu quả.

(phải có using System.Linq;)

 int maxValue = anArray.Max();
 int maxIndex = anArray.ToList().IndexOf(maxValue);

11
Bạn tiết kiệm rất nhiều thời gian viết mã, nhưng cuối cùng bạn sẽ phải xem qua bộ sưu tập hai lần.
Garo Yeriazarian

11
Bạn thậm chí không cần .ToList(), mảng triển khai rõ ràngIList
milimoose 7/12/12

@GaroYeriazarian Nếu độ phức tạp tuyến tính quá nhiều đối với trường hợp sử dụng của bạn, bạn có thể cần phải loại bỏ nhiều hơn là chỉ giảm hệ số hằng số đi một phần ba. (Mặc dù rõ ràng đó không phải là một sự tối ưu hóa không đáng kể.)
millimoose

1
@ sa_ddam213 Mảng triển khai IListgiao diện, nhưng chúng thực hiện một cách rõ ràng: msdn.microsoft.com/en-us/library/… . (Mảng cũng triển khai IList<T>giao diện chung tương ứng .)
millimoose 7/12/12

1
@ sa_ddam213 Không, hợp đồng ToList()là luôn sao chép. Sẽ là một ý tưởng khủng khiếp nếu phương pháp này đôi khi sao chép và đôi khi không - điều này sẽ dẫn đến lỗi răng cưa khá điên rồ. Trong thực tế việc thực hiện ToList()là nhiều hơn hoặc ít hơnreturn new List(source)
millimoose

44
int[] anArray = { 1, 5, 2, 7 };
// Finding max
int m = anArray.Max();

// Positioning max
int p = Array.IndexOf(anArray, m);

28

Nếu chỉ mục không được sắp xếp, bạn phải lặp qua mảng ít nhất một lần để tìm giá trị cao nhất. Tôi sẽ sử dụng một forvòng lặp đơn giản :

int? maxVal = null; //nullable so this works even if you have all super-low negatives
int index = -1;
for (int i = 0; i < anArray.Length; i++)
{
  int thisNum = anArray[i];
  if (!maxVal.HasValue || thisNum > maxVal.Value)
  {
    maxVal = thisNum;
    index = i;
  }
}

Điều này dài dòng hơn một cái gì đó sử dụng LINQ hoặc các giải pháp một dòng khác, nhưng nó có thể nhanh hơn một chút. Thực sự không có cách nào để thực hiện điều này nhanh hơn O (N).


4
Bạn có thể lưu một lần lặp bằng cách khởi tạo maxValthành giá trị mảng ở chỉ số 0 (giả sử mảng có độ dài ít nhất là 1), indexthành 0 và bắt đầu vòng lặp for tại i = 1.
Jon Schneider

14

LINQ bắt buộc một [1] -liner:

var max = anArray.Select((value, index) => new {value, index})
                 .OrderByDescending(vi => vi.value)
                 .First();

(Việc sắp xếp có thể là một hiệu suất vượt trội so với các giải pháp khác.)

[1]: Cho các giá trị đã cho của "một".


14
Chỉ cần thêm giải pháp này là độ phức tạp O (nlogn) tốt nhất. Tìm tối đa có thể đạt được trong thời gian O (n) cho một mảng không được sắp xếp.
dopplesoldner

13

Một lớp lót ngắn gọn:

var max = anArray.Select((n, i) => (Number: n, Index: i)).Max();

Trường hợp thử nghiệm:

var anArray = new int[] { 1, 5, 2, 7 };
var max = anArray.Select((n, i) => (Number: n, Index: i)).Max();
Console.WriteLine($"Maximum number = {max.Number}, on index {max.Index}.");
// Maximum number = 7, on index 4.

Đặc trưng:

  • Sử dụng Linq (không được tối ưu hóa như vani, nhưng đánh đổi là ít mã hơn).
  • Không cần phải sắp xếp.
  • Độ phức tạp tính toán: O (n).
  • Độ phức tạp không gian: O (n).

Nhận xét:

  • Đảm bảo rằng số (chứ không phải chỉ mục) là phần tử đầu tiên trong bộ tuple vì việc sắp xếp bộ tuple được thực hiện bằng cách so sánh các mục từ trái sang phải.

cái này thực sự gọn gàng !!
floydheld

Cần lưu ý rằng để điều này hoạt động, mục được tăng tối đa trước tiên phải là thứ
Caius Jard

Ý bạn là gì @CaiusJard? Như được hiển thị trong trường hợp kiểm tra, mục tối đa đã được tìm thấy chính xác nó là mục cuối cùng.
Lesair Valmont

Đầu tiên trong Tuple, ví dụ: anArray.Select((n, i) => ( Index: i, Number: n)).Max()tìm chỉ số tối đa thay vì số tối đa do cách so sánh các bộ giá trị (item1 là quan trọng nhất, v.v.)
Caius Jard

Đủ công bằng @CaiusJard, tôi đã thêm một nhận xét để chỉ ra điều đó. Cảm ơn.
Lesair Valmont,

3

Đây là hai cách tiếp cận. Bạn có thể muốn thêm xử lý khi mảng trống.

public static void FindMax()
{
    // Advantages: 
    // * Functional approach
    // * Compact code
    // Cons: 
    // * We are indexing into the array twice at each step
    // * The Range and IEnumerable add a bit of overhead
    // * Many people will find this code harder to understand

    int[] array = { 1, 5, 2, 7 };

    int maxIndex = Enumerable.Range(0, array.Length).Aggregate((max, i) => array[max] > array[i] ? max : i);
    int maxInt = array[maxIndex];

    Console.WriteLine($"Maximum int {maxInt} is found at index {maxIndex}");
}

public static void FindMax2()
{
    // Advantages: 
    // * Near-optimal performance

    int[] array = { 1, 5, 2, 7 };
    int maxIndex = -1;
    int maxInt = Int32.MinValue;

    // Modern C# compilers optimize the case where we put array.Length in the condition
    for (int i = 0; i < array.Length; i++)
    {
        int value = array[i];
        if (value > maxInt)
        {
            maxInt = value;
            maxIndex = i;
        }
    }

    Console.WriteLine($"Maximum int {maxInt} is found at index {maxIndex}");
}

1
anArray.Select((n, i) => new { Value = n, Index = i })
    .Where(s => s.Value == anArray.Max());

Đây là giải pháp O (n ^ 2), bởi vì bạn đang tính toán anArray.Max () trên mỗi lần lặp. Điều đó sẽ rất chậm đối với các mảng lớn.
Neil

1
int[] numbers = new int[7]{45,67,23,45,19,85,64}; 
int smallest = numbers[0]; 
for (int index = 0; index < numbers.Length; index++) 
{ 
 if (numbers[index] < smallest) smallest = numbers[index]; 
} 
Console.WriteLine(smallest);

1

Đầu ra cho mã dưới đây:

00: 00: 00.3279270 - max1 00: 00: 00.2615935 - max2 00: 00: 00.6010360 - max3 (arr.Max ())

Với 100000000 ints trong mảng không có sự khác biệt quá lớn nhưng vẫn ...

class Program
    {
        static void Main(string[] args)
        {
            int[] arr = new int[100000000];

            Random randNum = new Random();
            for (int i = 0; i < arr.Length; i++)
            {
                arr[i] = randNum.Next(-100000000, 100000000);
            }
            Stopwatch stopwatch1 = new Stopwatch();
            Stopwatch stopwatch2 = new Stopwatch();
            Stopwatch stopwatch3 = new Stopwatch();
            stopwatch1.Start();

            var max = GetMaxFullIterate(arr);

            Debug.WriteLine( stopwatch1.Elapsed.ToString());


            stopwatch2.Start();
            var max2 = GetMaxPartialIterate(arr);

            Debug.WriteLine( stopwatch2.Elapsed.ToString());

            stopwatch3.Start();
            var max3 = arr.Max();
            Debug.WriteLine(stopwatch3.Elapsed.ToString());

        }



 private static int GetMaxPartialIterate(int[] arr)
        {
            var max = arr[0];
            var idx = 0;
            for (int i = arr.Length / 2; i < arr.Length; i++)
            {
                if (arr[i] > max)
                {
                    max = arr[i];
                }

                if (arr[idx] > max)
                {
                    max = arr[idx];
                }
                idx++;
            }
            return max;
        }


        private static int GetMaxFullIterate(int[] arr)
        {
            var max = arr[0];
            for (int i = 0; i < arr.Length; i++)
            {
                if (arr[i] > max)
                {
                    max = arr[i];
                }
            }
            return max;
        }

1
 public static class ArrayExtensions
{
    public static int MaxIndexOf<T>(this T[] input)
    {
        var max = input.Max();
        int index = Array.IndexOf(input, max);
        return index;
    }
}

Điều này hoạt động cho tất cả các loại biến ...

var array = new int[]{1, 2, 4, 10, 0, 2};
var index = array.MaxIndexOf();


var array = new double[]{1.0, 2.0, 4.0, 10.0, 0.0, 2.0};
var index = array.MaxIndexOf();

1
public static void Main()
{
    int a,b=0;
    int []arr={1, 2, 2, 3, 3, 4, 5, 6, 5, 7, 7, 7, 100, 8, 1};

    for(int i=arr.Length-1 ; i>-1 ; i--)
        {
            a = arr[i];

            if(a > b)
            {
                b=a;    
            }
        }
    Console.WriteLine(b);
}

0
int[] Data= { 1, 212, 333,2,12,3311,122,23 };
int large = Data.Max();
Console.WriteLine(large);

1
Câu trả lời của bạn chỉ đưa ra giá trị cao nhất, nhưng người hỏi đã yêu cầu cả giá trị cao nhất và chỉ mục của giá trị cao nhất.
Cardin

0

Đây là một giải pháp LINQ là O (n) với các hệ số không đổi phù hợp:

int[] anArray = { 1, 5, 2, 7, 1 };

int index = 0;
int maxIndex = 0;

var max = anArray.Aggregate(
    (oldMax, element) => {
        ++index;
        if (element <= oldMax)
            return oldMax;
        maxIndex = index;
        return element;
    }
);

Console.WriteLine("max = {0}, maxIndex = {1}", max, maxIndex);

Nhưng bạn thực sự nên viết một forlop rõ ràng nếu bạn quan tâm đến hiệu suất.


0

Chỉ là một góc nhìn khác bằng cách sử dụng DataTable. Khai báo a DataTablevới 2 cột được gọi là indexval. Thêm một AutoIncrementtùy chọn và cả hai AutoIncrementSeedAutoIncrementStepcác giá trị 1vào indexcột. Sau đó, sử dụng một foreachvòng lặp và chèn từng mục mảng vào datatabledưới dạng một hàng. Sau đó, bằng Selectphương pháp sử dụng , hãy chọn hàng có giá trị lớn nhất.

int[] anArray = { 1, 5, 2, 7 };
DataTable dt = new DataTable();
dt.Columns.AddRange(new DataColumn[2] { new DataColumn("index"), new DataColumn("val")});
dt.Columns["index"].AutoIncrement = true;
dt.Columns["index"].AutoIncrementSeed = 1;
dt.Columns["index"].AutoIncrementStep = 1;
foreach(int i in anArray)
    dt.Rows.Add(null, i);

DataRow[] dr = dt.Select("[val] = MAX([val])");
Console.WriteLine("Max Value = {0}, Index = {1}", dr[0][1], dr[0][0]);

Đầu ra

Max Value = 7, Index = 4

Tìm bản demo ở đây


0

Tìm số lớn nhất và số nhỏ nhất trong mảng:

int[] arr = new int[] {35,28,20,89,63,45,12};
int big = 0;
int little = 0;

for (int i = 0; i < arr.Length; i++)
{
    Console.WriteLine(arr[i]);

    if (arr[i] > arr[0])
    {
        big = arr[i];
    }
    else
    {
        little = arr[i];

    }
}

Console.WriteLine("most big number inside of array is " + big);
Console.WriteLine("most little number inside of array is " + little);

1
nó sẽ trả về giá trị cuối cùng lớn hơn / nhỏ hơn giá trị đầu tiên trong mảng, không phải giá trị min / max.
Tomer Wolberg

0

Nếu bạn biết chỉ mục tối đa truy cập giá trị tối đa là ngay lập tức. Vì vậy, tất cả những gì bạn cần là chỉ số tối đa.

int max=0;

for(int i = 1; i < arr.Length; i++)
    if (arr[i] > arr[max]) max = i;

0

Đây là phiên bản C #. Nó dựa trên ý tưởng sắp xếp mảng.

public int solution(int[] A)
 {
    // write your code in C# 6.0 with .NET 4.5 (Mono)
    Array.Sort(A);
    var max = A.Max();
    if(max < 0)
        return 1;
    else
        for (int i = 1; i < max; i++)
        {
            if(!A.Contains(i)) {
                return i;
            }
        }
    return max + 1;
}


0

Hãy xem xét những điều sau:

    /// <summary>
    /// Returns max value
    /// </summary>
    /// <param name="arr">array to search in</param>
    /// <param name="index">index of the max value</param>
    /// <returns>max value</returns>
    public static int MaxAt(int[] arr, out int index)
    {
        index = -1;
        int max = Int32.MinValue;

        for (int i = 0; i < arr.Length; i++)
        {
            if (arr[i] > max)
            { 
                max = arr[i];
                index = i;
            }
        }

        return max;
    }

Sử dụng:

int m, at;
m = MaxAt(new int[]{1,2,7,3,4,5,6}, out at);
Console.WriteLine("Max: {0}, found at: {1}", m, at);

0

Điều này có thể được thực hiện với một forvòng không có thân, nếu chúng ta đang hướng tới chơi gôn;)

//a is the array


int mi = a.Length - 1;
for (int i=-1; ++i<a.Length-1; mi=a[mi]<a[i]?i:mi) ;

Kiểm tra ++i<a.Length-1bỏ sót kiểm tra chỉ mục cuối cùng. Chúng tôi không bận tâm về điều này nếu chúng tôi thiết lập nó như thể chỉ mục tối đa là chỉ mục cuối cùng để bắt đầu .. Khi vòng lặp chạy cho các phần tử khác, nó sẽ kết thúc và điều này hoặc điều khác là đúng:

  • chúng tôi đã tìm thấy một giá trị tối đa mới và do đó một chỉ số tối đa mới mi
  • chỉ số cuối cùng là giá trị tối đa, vì vậy chúng tôi không tìm thấy chỉ mục mới mivà chúng tôi mắc kẹt vớimi

Công việc thực sự được thực hiện bởi các công cụ sửa đổi vòng lặp sau:

  • giá trị tối đa ( a[mi]tức là mảng được lập chỉ mục bởi mi) mà chúng tôi tìm thấy cho đến nay có nhỏ hơn mục hiện tại không?
    • vâng, sau đó lưu trữ một cái mới mibằng cách ghi nhớ i,
    • không thì lưu trữ hiện có mi(no-op)

Khi kết thúc hoạt động, bạn có chỉ mục mà tại đó giá trị tối đa sẽ được tìm thấy. Về mặt logic thì giá trị tối đa làa[mi]

Tôi không thể hiểu rõ "tìm giá trị tối đa và chỉ mục của giá trị tối đa" thực sự cần thiết như thế nào để theo dõi giá trị tối đa, vì nếu bạn có một mảng và bạn biết chỉ số của giá trị tối đa, giá trị thực của giá trị tối đa là một trường hợp nhỏ khi sử dụng chỉ mục để lập chỉ mục mảng ..

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.