3 Höchsten werte aus 2d int array mit index

  • C#

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von Niko Ortner.

    3 Höchsten werte aus 2d int array mit index

    Hi Forum,
    ich bin neu hier und habe mal gleich eine kleine Frage:
    Ich habe ein zwei dimensionales Array mit Int werten. Nun möchte ich wissen, an welchen orten die 3 höchsten werte in diesem Array liegen. Hoffe mal, dass die Frage nicht vollkommen idiotisch ist und ich den Wald vor lauter bäumen nicht sehe.
    Danke für antworten im vorraus.
    @CogitoErgoSum31415 Willkommen im Forum. :thumbup:
    Besser wäre natürlich ein eindimensionales Array, das kannst Du sortieren und dann die drei ersten Werte nehmen.
    Ich eriß jetzt nicht, ob LINQ in diesem Kontext zweidimensionale Felder behandeln kann.
    Ich hab hier ein C#-Snippet (kannst Du ganz easy online konvertieren lassen), das kopiert das 2D-Array in ein 1D-Array. Dieses kannst Du mit Array.Sort(...) sortieren und die ersten 3 (oder letzten) Elemente auslesen.
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Windows.Forms;
    5. namespace WindowsFormsApplication1
    6. {
    7. public partial class Form1 : Form
    8. {
    9. public Form1()
    10. {
    11. this.InitializeComponent();
    12. }
    13. private void button1_Click(object sender, EventArgs e)
    14. {
    15. double[,] grid = { { 1, 2, 3 }, { 4, 5, 6 } };
    16. double d1 = this.Foo(grid);
    17. this.label1.Text = d1.ToString();
    18. }
    19. private double Foo(Array grid)
    20. {
    21. double[] arr = new double[grid.Length];
    22. System.Buffer.BlockCopy(grid, 0, arr, 0, grid.Length * sizeof(double));
    23. double d1 = ((IEnumerable<double>)arr).Average();
    24. return d1;
    25. }
    26. }
    27. }
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    @RodFromGermany

    Ich glaub das was du meinst ist das hier

    VB.NET-Quellcode

    1. Dim multiArray(,) As Int32 = {{22, 17, 22}, {45, 35, 95}, {85, 75, 74}}
    2. Dim bla = multiArray.Cast(Of Int32)().ToArray



    Eventuell könnte das ja ein Ansatz sein
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Public Module Module1
    4. Private rng As New Random
    5. Public Sub Main()
    6. Dim size1 As Int32 = 7
    7. Dim size2 As Int32 = 10
    8. Dim iArr2D(,) As Int32 = Create2DArray(size1, size2)
    9. Dim iMax() As MaxValue = New MaxValue(2) {}
    10. For i As Int32 = 0 To 2
    11. iMax(i) = New MaxValue With {.value = 0, .x = 0, .y = 0}
    12. Next
    13. For i As Int32 = 0 To size1 - 1
    14. For j As Int32 = 0 To size2 - 1
    15. For z As Int32 = 2 To 0 Step -1
    16. If iArr2D(i, j) > iMax(z).value Then
    17. SetMaxArr(iMax, iArr2D(i, j), i, j, z)
    18. Exit For
    19. End If
    20. Next
    21. Next
    22. Next
    23. For Each mv As MaxValue In iMax
    24. With mv
    25. Console.Write("{0}{1}", .value, vbTab)
    26. Console.Write("{0}{1}", .x, vbTab)
    27. Console.Write("{0}{1}", .y, vbTab)
    28. End With
    29. Console.WriteLine()
    30. Next
    31. Console.ReadLine()
    32. End Sub
    33. Private Sub SetMaxArr(ByRef arr() As MaxValue, ByVal val As Int32, ByVal x As Int32, ByVal y As Int32, ByVal z As Int32)
    34. Dim lst As New List(Of MaxValue)(arr)
    35. lst(z).value = val
    36. lst(z).x = x
    37. lst(z).y = y
    38. arr = (From s In arr Order By s Descending Select s).ToArray
    39. End Sub
    40. Private Function Create2DArray(ByVal s1 As Int32, ByVal s2 As Int32) As Int32(,)
    41. If s1 > 0 AndAlso s2 > 0 Then
    42. Dim res(,) = New Int32(s1 - 1, s2 - 1) {}
    43. For i As Int32 = 0 To s1 - 1
    44. For j As Int32 = 0 To s2 - 1
    45. res(i, j) = rng.Next(Int32.MaxValue)
    46. Next
    47. Next
    48. Return res
    49. End If
    50. Return Nothing
    51. End Function
    52. End Module
    53. Public Class MaxValue
    54. Implements IComparable
    55. Public value As Int32
    56. Public x As Int32
    57. Public y As Int32
    58. Public Function CompareTo(ByVal obj As Object) As Integer Implements System.IComparable.CompareTo
    59. Return Me.value.CompareTo(DirectCast(obj, MaxValue).value)
    60. End Function
    61. End Class


    Freundliche Grüsse

    exc-jdbi

    RodFromGermany schrieb:

    (kannst Du ganz easy online konvertieren lassen)
    Nicht nötig, im Titel steht C#?

    RodFromGermany schrieb:

    sortieren und die ersten 3 (oder letzten) Elemente auslese
    Er möchte nicht die 3 höchsten Werte, sonder die Positionen der 3 höchsten Werte.

    C#-Quellcode

    1. int[,] array = new int[0, 0]; //Dein Array
    2. SortedList<int, KeyValuePair<int, int>> sortedList = new SortedList<int, KeyValuePair<int, int>>();
    3. for (int y = 0; y < array.GetUpperBound(1); y++) {
    4. for (int x = 0; x < array.GetUpperBound(0); x++) {
    5. sortedList.Add(array[x, y], new KeyValuePair<int, int>(x, y));
    6. }
    7. }
    8. int firstX = sortedList.Values[sortedList.Count - 1].Key;
    9. int firstY = sortedList.Values[sortedList.Count - 1].Value;
    10. int secondX = sortedList.Values[sortedList.Count - 2].Key;
    11. int secondY = sortedList.Values[sortedList.Count - 2].Value;
    12. int thirdX = sortedList.Values[sortedList.Count - 3].Key;
    13. int thirdY = sortedList.Values[sortedList.Count - 3].Value;

    Bluespide schrieb:

    sonder die Positionen der 3 höchsten Werte.
    Die Liste sortieren und eine durchnumerierte Liste mit den Platzziffern mit sortieren.
    Array.Sort(TargetList, Platzziffern)
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    @Bluespide

    Mhhhhh ... Die Resultate sehen irgendwie komisch aus, und die Möglichkeiten der SordetList habe ich au noch nicht genau ins Detail angeschaut.

    Aber wenn ich z.B. 3x die grössten Werte einmal von X, und einmal von Y will, und das auf konventionellem Wege mache, dann würde das ungefähr so aussehen.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Public Module Module1
    4. Private rng As New Random
    5. Public Sub Main()
    6. Dim size1 As Int32 = 10
    7. Const size2 As Int32 = 2 'Const
    8. Dim iArr2D(,) As Int32 = Create2DArray(size1, size2)
    9. Dim sortedList As New SortedList(Of Int32, KeyValuePair(Of Int32, Int32))()
    10. For x As Int32 = 0 To iArr2D.GetUpperBound(0)
    11. For y As Integer = 0 To iArr2D.GetUpperBound(1)
    12. sortedList.Add(iArr2D(x, y), New KeyValuePair(Of Int32, Int32)(x, y))
    13. Next
    14. Next
    15. '************************************************************************
    16. '************************************************************************
    17. Dim LastCount = sortedList.Count - 1
    18. Dim Cnt0 As Int32 = -1, Cnt1 As Int32 = -1
    19. For i As Int32 = LastCount To 0 Step -1
    20. If sortedList.Values(i).Value = 0 Then
    21. Cnt0 += 1
    22. Else : Cnt1 += 1
    23. End If
    24. If (Cnt0 < 3) AndAlso (sortedList.Values(i).Value = 0) Then
    25. Console.Write("{0}{1}", sortedList.ElementAt(i), vbTab)
    26. Console.WriteLine()
    27. ElseIf (Cnt1 < 3) AndAlso (sortedList.Values(i).Value = 1) Then
    28. Console.Write("{0}{1}", sortedList.ElementAt(i), vbTab)
    29. Console.WriteLine()
    30. End If
    31. If (Cnt0 >= 3) AndAlso (Cnt1 >= 3) Then
    32. Exit For
    33. End If
    34. Next
    35. Console.WriteLine()
    36. Console.WriteLine()
    37. '************************************************************************
    38. '************************************************************************
    39. Console.ReadLine()
    40. End Sub
    41. Private Function Create2DArray(ByVal s1 As Int32, ByVal s2 As Int32) As Int32(,)
    42. If s1 > 0 AndAlso s2 > 0 Then
    43. Dim res(,) = New Int32(s1 - 1, s2 - 1) {}
    44. For i As Int32 = 0 To s1 - 1
    45. For j As Int32 = 0 To s2 - 1
    46. res(i, j) = rng.Next(Int32.MaxValue)
    47. Next
    48. Next
    49. Return res
    50. End If
    51. Return Nothing
    52. End Function
    53. End Module


    Edit:
    Gefunden:

    C#-Quellcode

    1. SortedList<Int32, KeyValuePair<Int32, Int32>> sortedList = new SortedList<Int32, KeyValuePair<Int32, Int32>>();
    2. for (Int32 x = 0; x <= iArr2D.GetUpperBound(0); x++)
    3. for (int y = 0; y <= iArr2D.GetUpperBound(1); y++)
    4. sortedList.Add(iArr2D[x, y], new KeyValuePair<Int32, Int32>(x, y));


    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „exc-jdbi“ ()

    Wie wäre es das Ganze über Datatables zu lösen.
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Linq;
    3. using System.Data;
    4. namespace ConsoleApplication1
    5. {
    6. class Program
    7. {
    8. static void Main(string[] args)
    9. {
    10. DataTable dt = new DataTable("Koordinaten");
    11. dt.Columns.Add("ID");
    12. dt.Columns.Add("X");
    13. dt.Columns.Add("Y");
    14. dt.Rows.Add(0, 19, 21);
    15. dt.Rows.Add(1, 10, 20);
    16. dt.Rows.Add(2, 13, 29);
    17. dt.Rows.Add(3, 12, 22);
    18. dt.Rows.Add(4, 11, 23);
    19. dt.Rows.Add(5, 17, 24);
    20. dt.Rows.Add(6, 16, 28);
    21. dt.Rows.Add(7, 18, 25);
    22. dt.Rows.Add(8, 14, 27);
    23. dt.Rows.Add(9, 15, 26);
    24. DataTable top3x = dt.Rows.Cast<DataRow>().OrderByDescending(x => x["X"]).Take(3).CopyToDataTable();
    25. DataTable top3y = dt.Rows.Cast<DataRow>().OrderByDescending(y => y["Y"]).Take(3).CopyToDataTable();
    26. foreach (DataRow dr in top3x.Rows)
    27. {
    28. Console.WriteLine("Top 3 of X: " + string.Join("; ", dr.ItemArray));
    29. }
    30. Console.WriteLine();
    31. foreach (DataRow dr in top3y.Rows)
    32. {
    33. Console.WriteLine("Top 3 of Y: " + string.Join("; ", dr.ItemArray));
    34. }
    35. Console.ReadKey();
    36. }
    37. }
    38. }
    Hab noch kurz Zeit gefunden um einen Test zu machen.

    Die SordetList ist für wenige Werte so bis 10'000 Koordinatenwerte gut zu gebrauchen. Nachher klar unbrauchbar (Absturz).
    Die LINQ-Variante (siehe unten) sieht zwar toll aus, ist aber extrem langsam, und macht bei (5000,256) schlapp. (Liegt wahrscheinlich bei mir am älteren Modell)

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. 'LINQ sehen zwar toll aus, sind aber sehr langsam
    4. 'Bei (5'000,256) macht diese Variante schlapp.
    5. Public Module LINQVariant
    6. Private rng As New Random
    7. Public Sub Main()
    8. Dim size1 As Int32 = 5000
    9. Dim size2 As Int32 = 256
    10. Dim bPrint As Boolean = True
    11. Dim sw As New Stopwatch
    12. '* MultiArray *******************************************************************
    13. Dim iMultiArray2D(,) As Int32 = Create2DArray(size1, size2)
    14. 'Cast zum Typ MaxValue, damit VXY (Value,X-Value,Y-Value) bekannt sind
    15. Dim mv() As MaxValue = CastToMaxValueType(iMultiArray2D)
    16. sw.Restart()
    17. 'Dev-Sort der Values
    18. Dim mv_DevV = mv.Cast(Of MaxValue).OrderByDescending(Function(m) m.value).ToArray
    19. sw.Stop()
    20. 'Dev-Sort der X-Values
    21. Dim mv_DevX = mv.Cast(Of MaxValue).OrderByDescending(Function(m) m.x).ToArray
    22. 'Dev-Sort der Y-Value
    23. Dim mv_DevY = mv.Cast(Of MaxValue).OrderByDescending(Function(m) m.y).ToArray
    24. Console.WriteLine("MultiArray Size: ({0} : {1}) {2}ms", size1, size2, sw.ElapsedMilliseconds)
    25. Console.WriteLine("**************************************************")
    26. If bPrint Then Print(mv_DevV, 3)
    27. '* JaggedArray ******************************************************************
    28. 'Dim iJagArr2D = Create2DJaggedArray(size1,size2)
    29. Dim iJagArr2D = CastJagged(iMultiArray2D) 'Gleiche Array als Jagged
    30. 'Cast zum Typ MaxValue, damit VXY (Value,X-Value,Y-Value) bekannt sind
    31. Dim mv2() As MaxValue = CastToMaxValueType(iJagArr2D)
    32. sw.Restart()
    33. 'Dev-Sort der Values
    34. Dim mv2_DevV = mv2.Cast(Of MaxValue).OrderByDescending(Function(m) m.value).ToArray
    35. sw.Stop()
    36. 'Dev-Sort der X-Values
    37. Dim mv2_DevX = mv2.Cast(Of MaxValue).OrderByDescending(Function(m) m.x).ToArray
    38. 'Dev-Sort der Y-Value
    39. Dim mv2_DevY = mv2.Cast(Of MaxValue).OrderByDescending(Function(m) m.y).ToArray
    40. Console.WriteLine("JaggedArray Size: ({0} : {1}) {2}ms", size1, size2, sw.ElapsedMilliseconds)
    41. Console.WriteLine("**************************************************")
    42. If bPrint Then Print(mv2_DevV, 3)
    43. Console.WriteLine("FINISH")
    44. Console.ReadLine()
    45. End Sub
    46. Private Sub Print(ByVal mv() As MaxValue, Optional ByVal cnt As Int32 = 0)
    47. If (mv IsNot Nothing) AndAlso (mv.Length > 0) Then
    48. Dim inc As Int32 = 0
    49. If cnt = 0 Then cnt = mv.Length - 1 Else cnt -= 1
    50. For Each m As MaxValue In mv
    51. Console.Write("{0}{1}", m.value, vbTab)
    52. Console.Write("{0}{1}", m.x, vbTab)
    53. Console.Write("{0}", m.y, vbTab)
    54. Console.WriteLine()
    55. inc += 1 : If inc > cnt Then Exit For
    56. Next
    57. Console.WriteLine()
    58. End If
    59. End Sub
    60. Private Function CastToMaxValueType(ByVal iArr2D(,) As Int32) As MaxValue()
    61. If (iArr2D IsNot Nothing) AndAlso (iArr2D.Length > 0) Then
    62. Dim res As New List(Of MaxValue)
    63. For i As Int32 = 0 To iArr2D.GetUpperBound(0)
    64. For j As Int32 = 0 To iArr2D.GetUpperBound(1)
    65. res.Add(New MaxValue With {.value = iArr2D(i, j), .x = i, .y = j})
    66. Next
    67. Next
    68. Return res.ToArray
    69. End If
    70. Return Nothing
    71. End Function
    72. Private Function CastToMaxValueType(ByVal iJArr2D()() As Int32) As MaxValue()
    73. If (iJArr2D IsNot Nothing) AndAlso (iJArr2D.Length > 0) Then
    74. Dim lst As New List(Of Int32())(iJArr2D)
    75. Dim res As New List(Of MaxValue)
    76. For i As Int32 = 0 To iJArr2D.Length - 1
    77. For j As Int32 = 0 To iJArr2D(i).Length - 1
    78. res.Add(New MaxValue With {.value = iJArr2D(i)(j), .x = i, .y = j})
    79. Next
    80. Next
    81. Return res.ToArray
    82. End If
    83. Return Nothing
    84. End Function
    85. Private Function Create2DArray(ByVal s1 As Int32, ByVal s2 As Int32) As Int32(,)
    86. If s1 > 0 AndAlso s2 > 0 Then
    87. Dim res(,) = New Int32(s1 - 1, s2 - 1) {}
    88. For i As Int32 = 0 To s1 - 1
    89. For j As Int32 = 0 To s2 - 1
    90. res(i, j) = rng.Next(Int32.MaxValue)
    91. Next
    92. Next
    93. Return res
    94. End If
    95. Return Nothing
    96. End Function
    97. Private Function CastJagged(ByVal iarr(,) As Int32) As Int32()()
    98. If (iarr IsNot Nothing) AndAlso (iarr.Length > 0) Then
    99. Dim res()() = New Int32(iarr.GetUpperBound(0))() {}
    100. For i As Int32 = 0 To iarr.GetUpperBound(0)
    101. res(i) = New Int32(iarr.GetUpperBound(1)) {}
    102. For j As Int32 = 0 To iarr.GetUpperBound(1)
    103. res(i)(j) = iarr(i, j)
    104. Next
    105. Next
    106. Return res
    107. End If
    108. Return Nothing
    109. End Function
    110. Private Function Create2DJaggedArray(ByVal s1 As Int32, ByVal s2 As Int32) As Int32()()
    111. If s1 > 0 AndAlso s2 > 0 Then
    112. Dim res()() As Int32 = New Int32(s1 - 1)() {}
    113. For i As Int32 = 0 To s1 - 1
    114. res(i) = New Int32(s2 - 1) {}
    115. For j As Int32 = 0 To s2 - 1
    116. res(i)(j) = rng.Next(Int32.MaxValue)
    117. Next
    118. Next
    119. Return res
    120. End If
    121. Return Nothing
    122. End Function
    123. End Module
    124. Public Class MaxValue
    125. Public value As Int32
    126. Public x As Int32
    127. Public y As Int32
    128. End Class



    Freundliche Grüsse

    exc-jdbi

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „exc-jdbi“ ()

    Hier gibt es Erklärungsbedarf!
    Was soll zum Beispiel bei einem Array wie {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}} oder {{0, 0, 0}, {0, 0, 1}, {1, 1, 1}}, also wenn es mehr als nur drei höchste Werte gibt, zurückgegeben werden? Einfach die drei erstbesten Ergebnisse? Ist es egal? Darf man davon ausgehen, dass dieser Fall nie eintreten kann?

    Auf der folgenden Lösung lässt sich aufbauen:

    VB.NET-Quellcode

    1. Public Shared Sub Main(Args As String())
    2. Dim Items = {{9, 2, 3, 4, 5, 6, 7, 8},
    3. {1, 2, 3, 4, 5, 6, 7, 8},
    4. {1, 9, 3, 4, 5, 6, 7, 9},
    5. {1, 2, 3, 9, 5, 6, 7, 8},
    6. {1, 2, 3, 4, 5, 6, 7, 8},
    7. {1, 2, 3, 4, 5, 6, 7, 8},
    8. {1, 2, 3, 4, 5, 6, 7, 8},
    9. {1, 9, 3, 4, 5, 6, 7, 8}}
    10. Dim Cells = Enumerable.Range(0, Items.GetLength(0)).SelectMany(Function(y) Enumerable.Range(0, Items.GetLength(1)).Select(Function(x) New With {.X = x, .Y = y, .Value = Items(y, x)}))
    11. Dim MaximumValue = Cells.Max(Function(i) i.Value)
    12. Dim MaximumCells = Cells.Where(Function(i) i.Value = MaximumValue)
    13. For Each i In MaximumCells
    14. Console.WriteLine("[{0}, {1}] = {2}", i.Y, i.X, i.Value)
    15. Next
    16. Console.ReadLine()
    17. End Sub

    Äääh... C#...

    C#-Quellcode

    1. static void Main(string[] args)
    2. {
    3. int[,] Items = {{9, 2, 3, 4, 5, 6, 7, 8},
    4. {1, 2, 3, 4, 5, 6, 7, 8},
    5. {1, 9, 3, 4, 5, 6, 7, 9},
    6. {1, 2, 3, 9, 5, 6, 7, 8},
    7. {1, 2, 3, 4, 5, 6, 7, 8},
    8. {1, 2, 3, 4, 5, 6, 7, 8},
    9. {1, 2, 3, 4, 5, 6, 7, 8},
    10. {1, 9, 3, 4, 5, 6, 7, 8}};
    11. var Cells = Enumerable.Range(0, Items.GetLength(0)).SelectMany(y => Enumerable.Range(0, Items.GetLength(1)).Select(x => new {X = x, Y = y, Value = Items[y, x]}));
    12. var MaximumValue = Cells.Max(i => i.Value);
    13. var MaximumCells = Cells.Where(i => i.Value == MaximumValue);
    14. foreach (var i in MaximumCells)
    15. {
    16. Console.WriteLine("[{0}, {1}] = {2}", i.Y, i.X, i.Value);
    17. }
    18. Console.ReadLine();
    19. }

    Hui, eingerostet!
    MaximumCells binhaltet einfach alle Zellen, die den höchsten Wert haben. Z.B. mit MaximumCells.Take(3) kannst Du das Ergebnis auf drei solche Zellen beschrenken. Oder vorher noch sortieren, je nach dem, wie Du das dann brauchst.
    Zeile 11 sieht ein bisschen gruselig aus, geht aber einfach nur alle Zeilen durch, und darin alle Spalten, und baut sich für jede Zelle ein Objekt, das die Position (X und Y) und den Wert (Value) beinhaltet. Davon wird dann in Zeile 12 der höchste Wert rausgesucht und in Zeile 13 alle Zellen mit diesem höchsten Wert.

    Fröhliches Codegolfen, allerseits!
    "Luckily luh... luckily it wasn't poi-"
    -- Brady in Wonderland, 23. Februar 2015, 1:56
    Desktop Pinner | ApplicationSettings | OnUtils