C # ค้นหาค่าอาร์เรย์และดัชนีสูงสุด


93

ดังนั้นฉันจึงมีอาร์เรย์ตัวเลขที่ไม่ได้เรียงลำดับint[] anArray = { 1, 5, 2, 7 };และฉันต้องการรับทั้งค่าและดัชนีของค่าที่ใหญ่ที่สุดในอาร์เรย์ซึ่งจะเป็น 7 และ 3 ฉันจะทำอย่างไร


จนถึงตอนนี้ ive พยายามใช้เมธอด Max () จากนั้นใช้วิธีการค้นหาแบบไบนารีเพื่อรับดัชนีของค่าสูงสุดนั้น แต่ไม่ได้ผลเว้นแต่จะเรียงลำดับอาร์เรย์ดังนั้นฉันจึงไม่สามารถใช้มันได้เมื่อฉันพยายามให้ตัวเลขเป็นลบ
Edmund Rojas

@EdmundRojas คุณไม่จำเป็นต้องใช้การค้นหาไบนารี การค้นหาเชิงเส้นของ ol แบบธรรมดาใช้ได้ผลดีสำหรับรายการที่ไม่ได้เรียงลำดับ
มิลลิโมส

คำตอบ:


145

นี่ไม่ใช่วิธีที่มีเสน่ห์ที่สุด แต่ใช้ได้ผล

(ต้องมีusing System.Linq;)

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

11
คุณประหยัดเวลาในการเขียนโค้ดได้มาก แต่คุณจะต้องผ่านคอลเลคชันสองครั้ง
Garo Yeriazarian

11
คุณไม่จำเป็นต้องใช้.ToList()อาร์เรย์อย่างชัดเจนIList
มิลลิโมส

@GaroYeriazarian หากความซับซ้อนเชิงเส้นมากเกินไปสำหรับกรณีการใช้งานของคุณคุณอาจต้องโกนออกมากกว่าแค่ลดค่าคงที่ลงหนึ่งในสาม (แม้ว่าจะเห็นได้ชัดว่ามันไม่ใช่การปรับให้เหมาะสมเล็กน้อยก็ตาม)
มิลลิโมส

1
@ sa_ddam213 อาร์เรย์ใช้IListอินเตอร์เฟซ แต่พวกเขาทำเช่นนั้นอย่างชัดเจน: msdn.microsoft.com/en-us/library/... (อาร์เรย์ยังใช้IList<T>อินเทอร์เฟซทั่วไปที่เกี่ยวข้อง)
มิลลิโมส

1
@ sa_ddam213 ไม่สัญญาToList()คือต้องลอกเสมอ มันเป็นความคิดที่แย่มากที่จะมีวิธีการคัดลอกในบางครั้งและบางครั้งก็ไม่ได้ - สิ่งนี้จะนำไปสู่ข้อบกพร่องของนามแฝงที่ค่อนข้างบ้าคลั่ง ในความเป็นจริงการนำไปใช้ToList()นั้นมากหรือน้อยreturn new List(source)
มิลลิโมส


28

หากดัชนีไม่ได้เรียงลำดับคุณต้องวนซ้ำในอาร์เรย์อย่างน้อยหนึ่งครั้งเพื่อหาค่าสูงสุด ฉันจะใช้forลูปง่ายๆ:

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;
  }
}

นี่เป็นสิ่งที่ละเอียดกว่าสิ่งที่ใช้ LINQ หรือโซลูชันบรรทัดเดียวอื่น ๆ แต่อาจเร็วกว่าเล็กน้อย ไม่มีทางทำให้เร็วกว่า O (N) ได้จริงๆ


4
คุณสามารถบันทึกหนึ่งซ้ำโดยการเริ่มต้นmaxValกับค่าอาร์เรย์ที่ดัชนี 0 (สมมติว่าอาร์เรย์เป็นอย่างน้อยความยาว 1), index0 i = 1และเริ่มต้นสำหรับวงที่
Jon Schneider

14

LINQ ที่บังคับหนึ่ง[1] -liner:

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

(การเรียงลำดับน่าจะเป็นประสิทธิภาพที่ได้รับผลกระทบมากกว่าโซลูชันอื่น ๆ )

[1]:สำหรับค่าที่ระบุเป็น "หนึ่ง"


14
การเพิ่มโซลูชันนี้คือความซับซ้อนของ O (nlogn) ที่ดีที่สุด การหาค่าสูงสุดสามารถหาได้ในเวลา O (n) สำหรับอาร์เรย์ที่ไม่เรียงลำดับ
dopplesoldner

13

ซับเดียวสั้น ๆ :

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

กรณีทดสอบ:

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.

คุณสมบัติ:

  • ใช้ Linq (ไม่ได้ปรับให้เหมาะสมเท่ากับวานิลลา แต่การแลกเปลี่ยนจะน้อยกว่ารหัส)
  • ไม่จำเป็นต้องเรียงลำดับ
  • ความซับซ้อนในการคำนวณ: O (n)
  • ความซับซ้อนของพื้นที่: O (n)

หมายเหตุ:

  • ตรวจสอบให้แน่ใจว่าตัวเลข (ไม่ใช่ดัชนี) เป็นองค์ประกอบแรกในทูเปิลเนื่องจากการเรียงลำดับทูเปิลทำได้โดยการเปรียบเทียบรายการทูเปิลจากซ้ายไปขวา

นี่มันสุด ๆ !!
floydheld

ควรจะชี้ให้เห็นว่าเพื่อให้ได้ผลรายการที่กำลังขยายสูงสุดจะต้องเป็นอันดับแรก
Caius Jard

คุณหมายถึงอะไร @CaiusJard? ดังที่แสดงในกรณีทดสอบพบรายการสูงสุดอย่างถูกต้องและเป็นรายการสุดท้าย
Lesair Valmont

อันดับแรกในanArray.Select((n, i) => ( Index: i, Number: n)).Max()ทูเพิลตัวอย่างเช่นพบดัชนีสูงสุดแทนที่จะเป็นจำนวนสูงสุดเนื่องจากวิธีเปรียบเทียบทูเปิล (item1 มีความสำคัญมากที่สุดเป็นต้น)
Caius Jard

พอใช้ @CaiusJard ฉันเพิ่มข้อสังเกตเพื่อชี้ให้เห็นว่า ขอบคุณ.
Lesair Valmont

3

นี่คือสองแนวทาง คุณอาจต้องการเพิ่มการจัดการเมื่ออาร์เรย์ว่างเปล่า

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());

นี่คือโซลูชัน O (n ^ 2) เนื่องจากคุณกำลังคำนวณ anArray.Max () ในทุกๆการวนซ้ำ ซึ่งจะช้ามากสำหรับอาร์เรย์ขนาดใหญ่
นีล

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

เอาต์พุตสำหรับรหัสร้อง:

00: 00: 00.3279270 - สูงสุด 1 00: 00: 00.2615935 - สูงสุด 2 00: 00: 00.6010360 - สูงสุด 3 (arr.Max ())

ด้วย 100000000 ints ในอาร์เรย์ไม่แตกต่างกันมากนัก แต่ก็ยัง ...

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;
    }
}

ใช้ได้กับตัวแปรทุกประเภท ...

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
คำตอบของคุณให้ค่าสูงสุดเท่านั้น แต่ผู้ถามขอทั้งค่าสูงสุดและดัชนีของค่าสูงสุด
Cardin

0

นี่คือโซลูชัน LINQ ซึ่งเป็น O (n) ที่มีปัจจัยคงที่ที่เหมาะสม:

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);

แต่คุณควรเขียนคำพูดที่ชัดเจนforหากคุณสนใจเกี่ยวกับประสิทธิภาพ


0

DataTableเพียงอีกหนึ่งมุมมองที่ใช้ ประกาศDataTableที่มี 2 คอลัมน์ที่เรียกว่าและindex valเพิ่มAutoIncrementตัวเลือกและทั้งคู่AutoIncrementSeedและAutoIncrementStepค่า1ลงในindexคอลัมน์ จากนั้นใช้foreachลูปและแทรกแต่ละรายการอาร์เรย์ลงในdatatableเป็นแถว จากนั้นใช้Selectวิธีการเลือกแถวที่มีค่าสูงสุด

รหัส

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]);

เอาต์พุต

Max Value = 7, Index = 4

ค้นหาการสาธิตได้ที่นี่


0

ค้นหาตัวเลขที่ใหญ่ที่สุดและน้อยที่สุดในอาร์เรย์:

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
มันจะส่งคืนค่าสุดท้ายที่ใหญ่กว่า / เล็กกว่าค่าแรกในอาร์เรย์ไม่ใช่ค่าต่ำสุด / สูงสุด
Tomer Wolberg

0

หากคุณทราบว่าดัชนีสูงสุดเข้าถึงค่าสูงสุดจะเกิดขึ้นทันที ดังนั้นสิ่งที่คุณต้องมีคือดัชนีสูงสุด

int max=0;

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

0

นี่คือเวอร์ชัน C # มันขึ้นอยู่กับแนวคิดในการจัดเรียงอาร์เรย์

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

พิจารณาสิ่งต่อไปนี้:

    /// <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;
    }

การใช้งาน:

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

สิ่งนี้สามารถทำได้ด้วยการforวนซ้ำแบบไม่มีตัวตนถ้าเรามุ่งหน้าไปสู่การเล่นกอล์ฟ;)

//a is the array


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

การตรวจสอบการ++i<a.Length-1ละเว้นการตรวจสอบดัชนีสุดท้าย เราจะไม่สนใจสิ่งนี้หากเราตั้งค่าราวกับว่าดัชนีสูงสุดเป็นดัชนีสุดท้ายที่จะเริ่มต้นด้วย .. เมื่อลูปทำงานสำหรับองค์ประกอบอื่น ๆ มันจะเสร็จสิ้นและสิ่งหนึ่งหรือสิ่งอื่นเป็นจริง:

  • เราพบค่าสูงสุดใหม่และด้วยเหตุนี้ดัชนีสูงสุดใหม่ mi
  • ดัชนีสุดท้ายคือค่าสูงสุดตลอดเวลาดังนั้นเราจึงไม่พบสิ่งใหม่miและเราติดอยู่กับค่าเริ่มต้นmi

งานจริงทำได้โดยตัวปรับแต่งโพสต์ลูป:

  • ค่าสูงสุด ( a[mi]เช่นอาร์เรย์จัดทำดัชนีโดยmi) ที่เราพบน้อยกว่ารายการปัจจุบันหรือไม่
    • ใช่แล้วเก็บใหม่miโดยการจดจำi,
    • ไม่แล้วเก็บที่มีอยู่mi(no-op)

ในตอนท้ายของการดำเนินการคุณจะมีดัชนีที่จะพบค่าสูงสุด ตามเหตุผลแล้วค่าสูงสุดคือa[mi]

ฉันไม่ค่อยเห็นว่า "find max และ index of max" จำเป็นจริงๆในการติดตามค่าสูงสุดด้วยเช่นกันเนื่องจากถ้าคุณมีอาร์เรย์และคุณรู้ดัชนีของค่าสูงสุดค่าที่แท้จริงของค่าสูงสุด เป็นกรณีเล็กน้อยของการใช้ดัชนีเพื่อจัดทำดัชนีอาร์เรย์ ..

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.