0

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;
}
1
  • Are you forced to use arrays here, or can you possibly use some other datatype? Commented Sep 13, 2019 at 5:49

3 Answers 3

1

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 e.g. displaying this information somewhere I would actually recommend to rather use a proper custom type and a simple flat list like e.g.

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.

e.g. 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 e.g. 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

Sign up to request clarification or add additional context in comments.

Comments

1

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

3 Comments

I don't think this case demands ("you need to use Dictionary"?) the use of a dictionary. Only that it can be inferred that it would be one of the most appropriate structures. On that note, I think it would be appropriate to explain why a dictionary is appropriate in "person-to-data" cases like this, rather than other structures that could achieve the merging behaviour alone, like List<KeyValuePair>.
You assume, without any evidence, that there are no duplicit keys and if there are, that you can silently discard them. I think that is a dangerous approach.
Duplicated name is a business logic problem. Let's say two contestants with the same name have a tie score. How do we distinguish them anyway? Hence, it is safe to assume that they have to enter different names.
0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.