Pierre Dole Ответов: 2

C# Как заполнить 2D-массив массивом?


Я ищу умный способ заполнить 2D-массив массивом. 2D-массив представляет собой сетку со строками и ячейками. Входные данные (строка) для ячеек поступают из консоли.С readline(). Поэтому я разделил строку на массив строк и теперь хочу использовать этот массив строк для заполнения 2-го измерения массива данных.


string[,] data = new string[height, width]; //grid

for (int i = 0; i < height; i++)
{
    string[] line = Console.ReadLine().ToCharArray().Select(c => c.ToString()).ToArray();
    
    data[i] = line; // <- compiler don't like this
}



Пример:
входная строка - "abc".

линия выглядит так
строка[0] = = " a"
строка[1] = = " b"
строка[2] = = " c"

теперь я хочу иметь это
data[0][0] = = " a"
данные[0][1] = = " b"
данные[0][2] = = " c"

Что я уже пробовал:

Конечно, я мог бы использовать "для", но в этом случае важна каждая часть исполнения.

BillWoodruff

Если вы уточните свой вопрос, я отвечу кодом. Вот что нам нужно знать:

вы:

1. хотите сделать значение "ячейки" в 2d-массиве 2d-массивом

your2dary[0,0] возвращает массив ["a", " b"]

или...

2. вы хотите просто установить значение одной ячейки с помощью 2d-массива, где первое значение в 2d-массиве - это индекс строки, а второе-индекс столбца.

Это два разных сценария.

Можно создать класс, который позволит манипулировать массивом, как в scneario two, но я советую вам забыть об использовании сеттера, где вы заполняете 2d-массив, но используете только один индекс в сеттере: хотя это можно сделать, это умное программирование, которое действительно искажает способ использования массивов и, вероятно, вызовет у вас проблемы в будущем.

с наилучшими пожеланиями, бил/л

Garth J Lancaster

.. наверное, лучше, чем мой ответ на самом деле

Pierre Dole

То, что я ищу, - это результат:

data[0][0] == "a"
data[0][1] == "b"

BillWoodruff

Наконец вы говорите нам, что вы действительно хотите сделать, но вы не обновили свой первоначальный пост. Поддержка здесь-это улица с двусторонним движением. Когда вы пересмотрите свой оригинальный пост, чтобы он был понятен всем, кто его читает, я отвечу рабочим кодом.

Pierre Dole

Я обновил сообщение. Извините, что я не все понимаю. Мой английский немного беден. Спасибо Вам за терпение.

BillWoodruff

Привет, Пьер, не волнуйся; здесь часто требуется несколько обменов мнениями, чтобы прояснить вопрос, и я, и другие люди здесь действительно хотим быть полезными :) Я опубликую пример пользовательского индексатора в ближайшие 12 часов или около того.

Теперь, когда вы пересмотрели вопрос, я думаю, что есть еще одна необходимая информация: строка [,] всегда будет иметь одни и те же размеры (если, конечно, вы не измените ее размер, что требует некоторых усилий в C#). Бывает ли так, что пользователь вашей программы должен ввести одинаковое количество значений для каждой "строки" вашего массива ? Если пользователь может ввести различное количество значений для каждой "строки", то вы, возможно, получите некоторую эффективность, используя зубчатый массив. И в одном из ваших комментариев здесь вы показываете неровный массив ... но в вашем пересмотренном посте вы не используете зубчатый массив.

Итак, мольбы проясняют это. твое здоровье, Билл

Pierre Dole

Это звучит очень любезно. Кажется, я нашел нужное место. :)

Не беспокойтесь о вводе. Ни один пользователь никогда этого не увидит. Я просто пытаюсь решить головоломку в браузерной игре кодирования. :) Игровой метод ввода и вывода осуществляется через консоль чтения и записи.

Массив, который я удалил, был всего лишь неудачной попыткой что-то описать. Что-то вроде шага между 2 шагами.

2 Ответов

Рейтинг:
1

Garth J Lancaster

вы не можете использовать "addRange" - Функция Array.addRange[^] ?


BillWoodruff

+4 это очень хороший вопрос. Надеюсь, ОП прояснит, какова здесь их цель. Возможно ли, что здесь нужен неровный массив ?

Garth J Lancaster

да, я опубликовал его и не был доволен тем, что дал довольно узкий ответ, но потом подумал, что будет два исхода: а) если бы требования ОП были к зубчатому массиву, они наверняка вернулись бы и сказали об этом, или Б) как и вы, кто-то другой поставил бы его под сомнение

BillWoodruff

Привет, Гарт, ну, ОП показал в комментарии, наконец, что они используют неровный массив, но, пока они не обновят свой вопрос, я не собираюсь утруждать себя публикацией ответа и рабочего кода.

Рейтинг:
1

BillWoodruff

I. использование метода расширения: здесь мы просто упаковываем то, что вы сделали бы с помощью цикла for:

public static class ArrayExtensions
{
    public static void Array2dInsert<T>(this T[,] ary, int rowndx, int startcol, params T[] values)
    {
        if (ary.GetLength(0) < rowndx
            || ary.GetLength(1) < startcol)
        {
           throw new ArgumentOutOfRangeException("rowndx or startcol", "Error in Array2dInsert: Out of range row or column index");
        }

        if(values.Length > ary.GetLength(1) - startcol)
        {
           throw new ArgumentOutOfRangeException("values", "Error in Array2dInsert: Too many values");
        }

        foreach (var value in values)
        {
            ary[rowndx, startcol] = value;
            startcol++;
        }
    }
}
Тест: выполните этот код в каком-либо методе или EventHandler
int[,] intary = new int[2,6];

intary.Array2dInsert(0,0,100,200,300);
Обратите внимание,что с помощью этого метода расширения вы можете указать индекс в "строке" массива, в который вы хотите начать вставку значений.

II. использование класса с пользовательскими Индексаторами:

Я настоятельно рекомендую вам изучить следующие учебные пособия, прежде чем вы начнете читать это: [^],[^].

И, пожалуйста, просмотрите некоторые из многих статей об Индексаторах здесь, на CodeProject:[^].

Имейте в виду, что внутри .NET индексатор является метод.

Сначала давайте посмотрим, что можно сделать, но, имхо, делать не следует:
using System.Collections.Generic;

namespace ArrayUtilities
{
    public class Array2dEx<T>
    {
        private T[,] innerArray { set; get; }

        public Array2dEx(int sz1, int sz2)
        {
            innerArray = new T[sz1, sz2];
        }

        //  one value only indexer
        public T this[int ndx1, int ndx2]
        {
            get
            {
                return innerArray[ndx1, ndx2];
            }
            set
            {
                innerArray[ndx1, ndx2] = value;
            }
        }

        // multiple value indexer
        public  IEnumerable<T> this[int ndx1, params T[] args]
        {
            set
            {
                for (int i = 0; i < args.Length; i++)
                {
                    innerArray[ndx1, i] = args[i];
                }
            }
            
            get
            {
                for (int j = 0; j < innerArray.GetLength(1); j++)
                {
                    yield return innerArray[ndx1, j];
                }
            }
        }
    }
}
Пример использования этого класса:
// in some Method or EventHandler

Array2dEx<string> test1 = new Array2dEx<string>(4, 5);

// put a break-point here

test1[0, 0] = "hello";
test1[0, 1] = "goodbye";

// note 1
string[] testary = new string[] { "what", "where" };
test1[2, testary] = null;

// note 2
var row2 = test1[2];

var row2item2 = test1[2, 1];
Я предлагаю вам скопировать приведенный выше код в проект .NET и поставить точку останова в указанном месте, а затем пройти через код, проверяя значения с каждым шагом.

Класс Array2dEx-это универсальный класс, который содержит 2d-массив указанного вами типа и предоставляет два различных метода индексирования. Один из методов индексирования является заменой стандартного метода индексирования и является именно тем, что вы ожидаете от индекса 2d-массива.

Примечание 1: второй метод индексирования использует тот факт, что пользовательский индексатор может принимать произвольные параметры, включая, как показано в этом случае, список параметров любого размера (используя средство аргумента params).

Обратите внимание, что сеттер второго индексатора не использует параметр 'value, который предоставляет любое свойство; мы использовали 'null в качестве аргумента "выбрасывания". Подробнее об этом позже: сеттер должен иметь какое-то значение, передаваемое ему при вызове.

Примечание 2: здесь ' getter часть индексатора возвращает IEnumerable< T>

Почему вы не должны этого делать:

1. это странно, "хакерски" и обходит обычный синтаксис для работы с массивами.

2. кто-то еще в будущем может посмотреть на код и задаться вопросом, что происходит с тем, что, по-видимому, присваивает 'null необычному "материалу" между скобками.

.. Продолжение следует завтра ... то, что вы могли бы использовать, если бы использовали зубчатый массив, это, я думаю, гораздо лучше.