Quel est le meilleur moyen d'extraire un tableau à une dimension d'un tableau rectangulaire en C #?

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

  •  04-07-2019
  •  | 
  •  

Question

Dites que j'ai un tableau de chaîne rectangulaire - pas un tableau en escalier

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

Quel est le meilleur moyen d’en extraire un tableau unidimensionnel (une seule ligne ou une seule colonne)? Je peux le faire avec une boucle for, bien sûr, mais j'espère que .NET aura une méthode plus élégante intégrée.

Points bonus pour la conversion du tableau de chaînes extrait en un tableau d'objets.

Était-ce utile?

La solution

Pour un tableau rectangulaire:

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

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

Et pour un tableau déchiqueté:

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

Autres conseils

Vous pouvez transtyper un tableau de chaînes en tableau d'objets de manière triviale - l'inverse ne fonctionne pas. L'extraction actuelle doit utiliser une boucle for, pour autant que je sache: Array.Copy nécessite que les rangs source et cible soient identiques et Buffer.BlockCopy ne fonctionne que pour les tableaux de type valeur. Cela semble étrange cependant ...

Vous pouvez utiliser LINQ pour extraire une ligne ou une colonne dans une seule instruction, même si cela sera inefficace (car il construira une liste en interne, vous devrez alors le convertir en tableau, si vous le faites vous-même, vous pourrez préallouez le tableau à la bonne taille et copiez-le directement).

Copie d'une ligne ( rowNum est la ligne à copier):

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

Copie d'une colonne ( colNum est la colonne à copier):

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

Je ne suis pas sûr que ce soit vraiment meilleur / plus simple qu'une boucle foreach - en particulier si vous écrivez une méthode ExtractRow et une méthode ExtractColumn et les réutilisez .

Je voudrais juste clarifier (à l'aide de l'exemple et de ce qui est demandé).

Un tableau en escalier est un tableau de tableaux et est déclaré comme suit:

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

Par rapport à un tableau rectangulaire défini comme un tableau unique contenant plusieurs dimensions:

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

De ce fait, un tableau dentelé est IQueryable / IEnumerable car vous pouvez le parcourir pour recevoir un tableau à chaque itération. Alors qu'un tableau rectangulaire n'est pas , IQueryable / IEnumerable, car les éléments sont traités en pleine dimension (0,0 0,1..etc) n’aura pas la possibilité d’utiliser Linq ni aucune fonction prédéfinie créée pour Array dans ce cas.

Bien que vous puissiez parcourir le tableau une fois (et obtenir ce que vous voulez) comme ceci:

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

J'espère que cela vous aidera:)

LINQ est la réponse

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

Les lignes peuvent être facilement copiées à l'aide de 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);

Ceci copiera la première ligne dans le tableau de dimension unique.

J'ai créé une méthode d'extension. Je ne sais pas à propos de la 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;
      }
}

utilisation

// 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) ; 
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top