Qual è il modo migliore per estrarre un array monodimensionale da un array rettangolare in C #?

StackOverflow https://stackoverflow.com/questions/232545

  •  04-07-2019
  •  | 
  •  

Domanda

Supponi di avere un array di stringhe rettangolare, non un array frastagliato

string[,] strings = new string[8, 3];

Qual è il modo migliore per estrarre un array monodimensionale da questo (una singola riga o una singola colonna)? Posso farlo con un ciclo for, ovviamente, ma spero che .NET abbia un modo più elegante incorporato.

Punti bonus per convertire l'array di stringhe estratto in un array di oggetti.

È stato utile?

Soluzione

Per una matrice rettangolare:

string[,] rectArray = new string[3,3] { 
    {"a", "b", "c"}, 
    {"d", "e", "f"}, 
    {"g", "h", "i"} };

var rectResult = rectArray.Cast<object>().ToArray();

E per un array frastagliato:

string[][] jaggedArray =  { 
    new string[] {"a", "b", "c", "d"}, 
    new string[] {"e", "f"}, 
    new string[] {"g", "h", "i"} };

var jaggedResult = jaggedArray.SelectMany(s => s).Cast<object>().ToArray();

Altri suggerimenti

Puoi lanciare un array di stringhe su un array di oggetti in modo banale - andare dall'altra parte non funziona. L'estrazione effettiva deve tuttavia utilizzare un ciclo for, per quanto posso vedere: Array.Copy richiede che i ranghi di origine e destinazione siano gli stessi e Buffer.BlockCopy funziona solo per array di tipi di valore. Sembra strano però ...

Puoi usare LINQ per aggiungere una riga o una colonna in una singola istruzione, anche se sarà inefficiente (poiché costruirà un elenco internamente, quindi dovrai convertirlo in un array - se lo fai da solo puoi preallocate l'array nella giusta dimensione e copiatelo direttamente).

Copia di una riga ( rowNum è la riga da copiare):

object[] row = Enumerable.Range(0, rowLength)
                         .Select(colNum => (object) stringArray[rowNum, colNum])
                         .ToArray();

Copia di una colonna ( colNum è la colonna da copiare):

object[] column = Enumerable.Range(0, columnLength)
                            .Select(rowNum => (object) stringArray[rowNum, colNum])
                            .ToArray();

Non sono sicuro che sia davvero migliore / più semplice di un ciclo foreach, in particolare se scrivi un metodo ExtractRow e un metodo ExtractColumn e riutilizzali .

Vorrei solo chiarire (dato l'esempio e cosa viene chiesto).

Un array frastagliato è un array di array ed è dichiarato così:

string[][] data = new string[3][];
data[0] = new string[] { "0,[0]", "0,[1]", "0,[2]" };
data[1] = new string[] { "1,[0]", "1,[1]", "1,[2]" ];
data[2] = new string[] { "2,[0]", "1,[1]", "1,[2]" };

Contro un array rettangolare definito come un singolo array che contiene più dimensioni:

string[,] data = new string[3,3];
data[0,0] = "0,0";
data[0,1] = "0,1";
data[0,2] = "0,2";
...etc

Per questo motivo, un array frastagliato è IQueryable / IEnumerable perché puoi iterare su di esso per ricevere un array ad ogni iterazione. Considerando che un array rettangolare non è non IQueryable / IEnumerable perché gli elementi sono indirizzati a dimensione intera (0,0 0,1..ecc.) In modo da non avrà la possibilità di usare Linq o qualsiasi funzione predefinita creata per Array in quel caso.

Anche se puoi iterare l'array una volta (e ottenere ciò che desideri) in questo modo:

/// INPUT: rowIndex, OUTPUT: An object[] of data for that row
int colLength = stringArray.GetLength(1);
object[] rowData = new object[colLength];
for (int col = 0; col < colLength; col++) {
    rowData[col] = stringArray[rowIndex, col] as object;
}
return rowData;

/// INPUT: colIndex, OUTPUT: An object[] of data for that column
int rowLength = stringArray.GetLength(0);
object[] colData = new object[rowLength];
for (int row = 0; r < rowLength; row++) {
    colData[row] = stringArray[row, colIndex] as object;
}
return colData;

Spero che questo aiuti :)

LINQ è la risposta

static object[] GetColumn(string[][] source, int col) {
    return source.Iterate().Select(x => source[x.Index][col]).Cast<object>().ToArray();
}
static object[] GetRow(string[][] source, int row) {
    return source.Skip(row).First().Cast<object>().ToArray();
}
public class Pair<T> {
    public int Index;
    public T Value;
    public Pair(int i, T v) {
        Index = i;
        Value = v;
    }
}
static IEnumerable<Pair<T>> Iterate<T>(this IEnumerable<T> source) {
    int index = 0;
    foreach (var cur in source) {
        yield return new Pair<T>(index, cur);
        index++;
    }
}

Le righe possono essere copiate facilmente utilizzando Array.Copy:

        int[][] arDouble = new int[2][];
        arDouble[0] = new int[2];
        arDouble[1] = new int[2];
        arDouble[0][0] = 1;
        arDouble[0][1] = 2;
        arDouble[1][0] = 3;
        arDouble[1][1] = 4;

        int[] arSingle = new int[arDouble[0].Length];

        Array.Copy(arDouble[0], arSingle, arDouble[0].Length);

Questo copierà la prima riga nell'array Dimension singolo.

ho creato il metodo di estensione. non so della performance.

public static class ExtensionMethods 
{
     public static string[] get1Dim(this string[,] RectArr, int _1DimIndex , int _2DimIndex   )
     {
        string[] temp = new string[RectArr.GetLength(1)];

        if (_2DimIndex == -1)
        {
          for (int i = 0; i < RectArr.GetLength(1); i++)
          {   temp[i] = RectArr[_1DimIndex, i];    }
        }
        else
        {
          for (int i = 0; i < RectArr.GetLength(0); i++)
          {   temp[i] = RectArr[  i , _2DimIndex];    }
        }

         return temp;
      }
}

utilizzo

// we now have this funtionaliy RectArray[1, * ]  
//                                       -1 means ALL    
string[] _1stRow = RectArray.get1Dim( 0, -1) ;    
string[] _2ndRow = RectArray.get1Dim( 1, -1) ; 

string[] _1stCol = RectArray.get1Dim( -1, 0) ;    
string[] _2ndCol = RectArray.get1Dim( -1, 1) ; 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top