简体   繁体   中英

How to join to multidimensional array

I have been trying to fix this problem for days and was wondering if anyone could help, I am still new to C# so any thing you can recommend would be a great help!

What I am trying to do is to save a new name/score into existing names/scores list.

I have already tried a number of different methods but with no luck.

Heres an example of what I am trying to do:

string[,] array1 = new string[,] { { "Bob", "100" } };
string[,] array2 = new string[,] { { "Dave", "200" }, { "Sam", "300" }, { "nick", "310" } };

So I would pass both arrays through the function below.

public static string[,] CombineArrayFunction(string[,] array1, string[,] array2)
{

    string[,] finalArray = new string[array1.Length + array2.Length, 2];

    Array.Resize<string[,]>(ref array1, array1.Length + array2.Length);

    Array.Copy(array2, 0, array1, array1.Length, array2.Length);

    for (int i = 0; i < finalArray.Length; i++)
    {
        finalArray[i, 0] = array1[i, 0];
        finalArray[i, 1] = array1[i, 1];
    }

    return finalArray;
}

You can use Dictionary. It's much simpler than a multi-dimensional array.

var dict1 = new Dictionary<string, string> { { "Bob", "100" } };
var dict2 = new Dictionary<string, string> { { "Dave", "200" }, { "Sam", "300" }, { "Nick", "310" } };
var combinedDict = dict1.Concat(dict2).GroupBy(d => d.Key).ToDictionary(d => d.Key, d => d.First().Value);

foreach (var item in combinedDict)
{
    Console.WriteLine($"{item.Key} - {item.Value}");
}

Result

Bob - 100
Dave - 200
Sam - 300
Nick - 310

you can't use

Array.Resize<string[,]>(ref array1, array1.Length + array2.Length);

since the elements in your array are not of type string[,] . It would work if you had a string[][] because then you could use

Array.Resize<string[]>(....);

For multidimensional arrays there is afaik no built-in method so you have to do it simply "manually"

public static string[,] CombineArrayFunction(string[,] array1, string[,] array2)
{
    var finalArray = new string[array1.Length + array2.Length, 2];

    // simply first run through the one array
    for (var i = 0; i < array1.Length; i++)
    {
        finalArray[i, 0] = array1[i, 0];
        finalArray[i, 1] = array1[i, 1];
    }

    // then run through the second array
    for (var i = 0; i < array2.Length; i++)
    {
        // simply add an offset to the index
        // according to the length of the first array
        finalArray[i + array1.Length - 1, 0] = array2[i, 0];
        finalArray[i + array1.Length - 1, 1] = array2[i, 1];
    }

    return finalArray;
}

However maybe the main issue is in your data structure itself.


A Dictionary as mentioned by Rawitas Krungkaew might be a better approach in the case you have unique keys because then it is also faster in access if you later are looking for a specific value.


If your use case is rather only about storing and eg displaying this information somewhere I would actually recommend to rather use a proper custom type and a simple flat list like eg

public List<ScoreEntry> scoreBoard = new List<ScoreEntry>();

[Serializable]
public class ScoreEntry
{
    public string Name;
    // or still string if you want to stick to that
    public int Score;

    public ScoreEntry(string name, int score)
    {
        Name = name;
        Score = score;
    }
}

then you could simply either add an item

scoreBoard.Add(new ScoreEntry("Bob", 100))

or if needed multiple ones using AddRange

scoreBoard.AddRange(new List<ScoreEntry>{new ScoreEntry("Bob", 100), new ScoreEntry("Marley", 200)});

There are a lot more advantages of this list.

For example it can be very simply iterated without having to care about two indices all the time.

And in particular for having a score board since you can now use all the magic from Linq ( using Syste.Linq; ) and filter and sort your list.

eg sort this list alphabetic

var alphabeticallyOrdererList = scoreBoard.OrderBy(e => e.Name).ToList();

or by score

var scoreOrderedList = scoreBoard.OrderByDescending(e => e.Score).ToList();

or use both to first order by score and if equal order by name

var scoreAndAlphabeticallyOrderedList = scoreBoard.OrderByDescending(e => e.Score).ThenBy(e => e.Name).ToList();

or return all entries belonging to "Bob"

var bobEntries = scoreBoard.Where(e => string.Equals(e.Name, "Bob")).ToList();

And if you then still need to access a certain entry Linq offers a lot of magic. For example find the maximum score for "Bob"

var entry = scoreBoard.Where(e => string.Equals(e.Name, "Bob")).OrderByDescending(e => e.Score).FirstOrDefault();

either returns the highest score of "Bob" or 0 if there was none in the list.


Another advantage of this list is that it is directly serializable so 1. You can actually see it in the Unity Inspector. It is saved if you eg fill it with some default values in the Inspector.

You can also directly serilaize and deserialize it to the most formats like XML, JSON (for those you need a wrapper class for the list) or simply in a textfile with one line per entry etc

Two dimensional array is not the best data structure for this (more in @derHugo post). To the actual code,

var finalArray = new string[array1.Length + array2.Length, 2];

array1.Length is total count of all items in all dimensions. What you really want is array1.GetLength(0) .

Array.Resize<string[,]>(ref array1, array1.Length + array2.Length);

you can not resize multidimensional array. If you could, you would not need the finalArray, as Resize creates new array anyway. But you can not.

Array.Copy(array2, 0, array1, array1.Length, array2.Length);

array1.Length no longer holds the size of original array. Now it returns size of the resized array, so this is a bug.

for (int i = 0; i < finalArray.Length; i++)
{
    finalArray[i, 0] = array1[i, 0];
    finalArray[i, 1] = array1[i, 1];
}

really no need to loop when you can use Array.Copy . Here is my code

public static string[,] CombineArrayFunction(string[,] array1, string[,] array2)
{
    if (array1.GetLength(1) != array2.GetLength(1))
    {
        throw new NotSupportedException("Arrays have to be the same size");
    }

    string[,] finalArray = new string[array1.GetLength(0) + array2.GetLength(0), array1.GetLength(1)];

    Array.Copy(array1, 0, finalArray, 0, array1.Length);
    Array.Copy(array2, 0, finalArray, array1.Length, array2.Length);

    return finalArray;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM