C# Changing only part of an array, in random places

I've got a 2D array of int's in a console c# code (7X3 'cells'). The moment I create it, it is initialized with zeros.

I've got to change the value of only five 'cells' into 1, without changing the value of other 'cells'. I know it is a basic thing, but, as an absolute rookie in C#, I can't get it to work, no matter what cell I use. Can you help me?

Thanks in advance.

(Note: As I am a frequent user/contributer, I know it looks like a classic "Do my homework" question and I apologize, but as I'm really stuck on this weenie part (and the rest of my project is OK), I'd appreciate the help).

Answers


Here are two ways of solving this issue, the first one; called BruteForceRandomImplementation is easy to implement and understand but quite slow once you attempt to mark a very large number of locations with 1s due to it's brute-force like usage of Random till it fills enough locations.

    /// <summary>
    /// This method uses a random based algorithm to create a two-dimensional array of [height, width] 
    /// with exactly locationsToFind locations set to 1. 
    /// </summary>
    /// <param name="height"></param>
    /// <param name="width"></param>
    /// <param name="locationsToFind"></param>
    /// <returns></returns>
    public int[,] BruteForceRandomImplementation(int height, int width, int locationsToFind)
    {
        var random = new Random();
        locationsToFind = LimitLocationsToFindToMaxLocations(height, width, locationsToFind);

        // Create our two-dimensional array.
        var map = new int[height, width];

        int locationsFound = 0;

        // Randomly set positons to 1 untill we have set locationsToFind locations to 1. 
        while (locationsFound < locationsToFind)
        {
            // Get a random Y location - limit the max value to our height - 1. 
            var randomY = random.Next(height);
            // Get a random X location - limit the max value to our width - 1. 
            var randomX = random.Next(width);

            // Find another random location if this location is already set to 1. 
            if (map[randomY, randomX] == 1)
                continue;

            // Otherwise set our location to 1 and increment the number of locations we've found.
            map[randomY, randomX] = 1;
            locationsFound += 1;
        }

        return map;
    }

With the following helper method to keep our locationsToFind range sane:

    /// <summary>
    /// Limits the locationsToFind variable to the maximum available locations. This avoids attempting to 
    /// mark more locations than are available for our width and height. 
    /// </summary>
    /// <param name="height"></param>
    /// <param name="width"></param>
    /// <param name="locationsToFind"></param>
    /// <returns></returns>
    public int LimitLocationsToFindToMaxLocations(int height, int width, int locationsToFind)
    {
        return Math.Min(locationsToFind, height * width);
    }

My second implementation called ShuffleImplementation is a lot faster when you are marking large numbers of unique locations. It creates a one-dimensional array, fills this with enough 1s to satisify your needs then shuffles this array using the Fisher-Yates shuffle to finally proceed to expand this one-dimensional array into a two-dimensional one:

    /// <summary>
    /// This method uses a shuffle based algorithm to create a two-dimensional array of [height, width] 
    /// with exactly locationsToFind locations set to 1. 
    /// </summary>
    /// <param name="height"></param>
    /// <param name="width"></param>
    /// <param name="locationsToFind"></param>
    /// <returns></returns>
    public int[,] ShuffleImplementation(int height, int width, int locationsToFind)
    {
        locationsToFind = LimitLocationsToFindToMaxLocations(height, width, locationsToFind);
        // Create a 1 dimensional array large enough to contain all our values. 
        var array = new int[height * width];

        // Set locationToFind locations to 1. 
        for (int location = 0; location < locationsToFind; location++)
            array[location] = 1;

        // Shuffle our array.
        Shuffle(array);

        // Now let's create our two-dimensional array.
        var map = new int[height, width];

        int index = 0;

        // Expand our one-dimensional array into a two-dimensional one. 
        for (int y = 0; y < height; y++)
        {
            for (int x = 0; x < width; x++)
            {
                map[y, x] = array[index];
                index++;
            }
        }

        return map;
    }

    /// <summary>
    /// Shuffles a one-dimensional array using the Fisher-Yates shuffle. 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="arr"></param>
    public static void Shuffle<T>(T[] array)
    {
        var random = new Random();

        for (int i = array.Length - 1; i > 0; i--)
        {
            int n = random.Next(i + 1);
            Swap(ref array[i], ref array[n]);
        }
    }

    /// <summary>
    /// Swaps two values around. 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="valueA"></param>
    /// <param name="valueB"></param>
    public static void Swap<T>(ref T valueA, ref T valueB)
    {
        T tempValue = valueA;
        valueA = valueB;
        valueB = tempValue;
    }

Usage:

var map = BruteForceRandomImplementation(7, 3, 5);

Or:

var map = ShuffleImplementation(7, 3, 5);

Depending on which one you want to use. For a good example of the performance difference between the two, try:

        int width = 1000;
        int height = 1000;
        int locationsToFind = (width * height) - 1;

        var stopwatch = new Stopwatch();

        stopwatch.Start();
        BruteForceRandomImplementation(height, width, locationsToFind);
        stopwatch.Stop();

        Console.WriteLine(string.Format("BruteForceRandomImplementation took {0}ms", stopwatch.ElapsedMilliseconds));

        stopwatch.Restart();
        ShuffleImplementation(height, width, locationsToFind);
        stopwatch.Stop();

        Console.WriteLine(string.Format("ShuffleImplementation took {0}ms", stopwatch.ElapsedMilliseconds));

On my laptop BruteForceRandomImplementation took 1205ms and ShuffleImplementation took 67ms or nearly 18x faster.


Need Your Help

Xcode how to replace quotation from a text?

objective-c xcode xcode4

I am parsing a xml link which has lots of quotations and I wanna replace it. I have used this code but the it won't run because of the quotations. So could you help me please?

Obtaining client IP address in WCF 3.0

wcf

Apparently you can easily obtain a client IP address in WCF 3.5 but not in WCF 3.0. Anyone know how?

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.