C# Beginner2 - Victory is close - Introduction to arrays in C# - Split the array

Привіт! Задачу вирішила, змінивши початок свого коду за підказкою від КодІзі, але до кінця підказку так і не зрозуміла.

Blockquote
Create 2 int arrays big and little of size myArray.Length.

Чому ми створюємо малий і великий масиви з такою довжиною (розумію, що це максимально можлива довжина для кожного з них), але не зрозуміло де в коді видно, що вона зменшується по мірі зміни bigIndex та littleIndex і де в коді взагалі видно зв’язок між ними?

Також мені не зовсім зрозумілий цей код (а саме, що відбувається з індексом елементу масиву - big[bigIndex++] = myArray[i] та little[littleIndex++] = myArray[i] )

for (int i = 0; i < myArray.Length; ++i)
{
    if (myArray[i] > 100)
        big[bigIndex++] = myArray[i];
    else
        little[littleIndex++] = myArray[i];
}

Моя початкова частина коду була такою:

 int[] myArray = GetNumbersFromConsole();
            int sizeBig = 0;
            int[] arrayBig = new int[sizeBig];
            int sizeLittle = 0;
            int[] arrayLittle = new int[sizeLittle];

            for (int i = 0; i < myArray.Length; ++i)
            {
                if (myArray[i] > 100)
                {
                    arrayBig[sizeBig] = myArray[i];
                    sizeBig = sizeBig + 1;
                }

                else
                {
                    arrayLittle[sizeLittle] = myArray[i];
                    sizeLittle = sizeLittle + 1;
                }
          }

Прокоментуйте будь-ласка:

  1. чому було неправильно початково створювати малий і великий масиви з розміром, рівним sizeBig та sizeLittle відповідно;

  2. чому неправильно збільшувати sizeBig та sizeLittle на одиницю після присвоєння кожному значенню великого/малого масиву i-го значення спільного масиву при виконанні умов приналежності до малого чи великого масивів

Наразі мій остаточний код, прийнятий як правильний:

using System;

namespace Arrays
{
    class SplitArray
    {
        public static void Main(string[] args)
        {
            int[] myArray = GetNumbersFromConsole();

            int sizeBig = 0;
            int[] arrayBig = new int[myArray.Length];
            int sizeLittle = 0;
            int[] arrayLittle = new int[myArray.Length];

            for (int i = 0; i < myArray.Length; ++i)
            {
                if (myArray[i] > 100)
                {
                    arrayBig[sizeBig++] = myArray[i];
                }

                else
                {
                    arrayLittle[sizeLittle++] = myArray[i];
                }             

            }

            Console.Write("Big: ");
             for (int j = 0; j < sizeBig; ++j)
                {
                    if (j == sizeBig - 1)
                    {
                        Console.WriteLine(arrayBig[j]);
                    }
                    else
                    {
                        Console.Write(arrayBig[j]);
                        Console.Write(" ");
                    }
                }

                Console.Write("Little: ");
                for (int k = 0; k < sizeLittle; ++k)
                {
                    if (k == sizeLittle - 1)
                    {
                        Console.WriteLine(arrayLittle[k]);
                    }
                    else
                    {
                        Console.Write(arrayLittle[k]);
                        Console.Write(" ");
                    }
                }
        }

        

        static int[] GetNumbersFromConsole()
        {
            int count = int.Parse(Console.ReadLine());
            int[] result = new int[count];

            for(int i = 0; i < count; ++i)
            {
                result[i] = int.Parse(Console.ReadLine());
            }

            return result;
        }
    }
}

А код КодІзі:

using System;

namespace Arrays
{
    class SplitArray
    {
        public static void Main(string[] args)
        {
            int[] myArray = GetNumbersFromConsole();

            int[] big = new int[myArray.Length];
            int bigIndex = 0;

            int[] little = new int[myArray.Length];
            int littleIndex = 0;

            for (int i = 0; i < myArray.Length; ++i)
            {
                if (myArray[i] > 100)
                    big[bigIndex++] = myArray[i];
                else
                    little[littleIndex++] = myArray[i];
            }

            Console.WriteLine($"Big: {ArrayToString(big, bigIndex)}");
            Console.WriteLine($"Little: {ArrayToString(little, littleIndex)}");
        }
        
        static string ArrayToString(int[] someArray, int actualSize)
        {
            string result = string.Empty;
            if (actualSize > 0)
            {
                for (int i = 0; i < actualSize - 1; ++i)
                    result += (someArray[i] + " ");

                result += someArray[actualSize - 1];
            }

            return result;
        }

        static int[] GetNumbersFromConsole()
        {
            int count = int.Parse(Console.ReadLine());
            int[] result = new int[count];

            for(int i = 0; i < count; ++i)
            {
                result[i] = int.Parse(Console.ReadLine());
            }

            return result;
        }
    }
}

Якщо знайдеться час, прокоментуйте також, будь ласка, ваше елегантне рішення з методом перетворення масиву в строку :heartpulse:

Почну з

але не зрозуміло де в коді видно, що вона зменшується по мірі зміни bigIndex та littleIndex

Все вірно, ви цього не бачите в коді, тому що масиви не змінюються у довжині.
Масиви створюються статичного розміру. Коли ви вказуєте int[number] - number відповідає за максимальний розмір.

Таким чином, якщо ви пишете int[10] - максимальний розмір масиву буде 10 елементів. Тепер можна підійти до:

  1. чому було неправильно початково створювати малий і великий масиви з розміром, рівним sizeBig та sizeLittle відповідно;

Давайте подивимось на ваш код.

int sizeBig = 0;
int[] arrayBig = new int[sizeBig];

значання sizeBig = 0;, тому ми можемо переписати ваш код як

int[] arrayBig = new int[0];

тобто максимальний розмір масиву - 0 (порожній масив). Ми не можемо в нього нічого записати.
Проблема полягає в тому, що вам невідомо на початку задачі скільки існує великих елементів і скільки існує малих елементів. Якби ця інформація була відома заздалегіть, то дійсно, було би більш доцільно створювати масиви “вірного” розміру.

Згадаємо дитинство. Село, картопля. Вам приносять повне відро викопаної картоплі, яку треба посортувати. Велика картопля іде в одне відро, мала іде в інше відро. Заздалегідь ніхто не знає скільки великої картоплі тільки що викопали. Можливо там вся велика, можливо там вся мала, може 50/50, або ж 30/70. Саме тому, для сортування вам дають два пустих відра ТАКОГО Ж розміру, що й відро з викопаною картоплею.
Поступово, перебираючи кожну картоплину, ви вибираєте в яке відро її кинути. Можливо було б більш доцільно, замість двох відр на 10л, взяти 6л для великої картоплі, та 4л для малої. Але наступне відро що вам підносять, може мати не 60/40 розподіл, а якийсь інший.

3 Likes

Це насправді правильно і вірно. Це іноді називаються синтаксичним цукром (“syntactic sugar”).

bigIndex++; - це саме приклад синтаксичного цукру, який пришвидшує написання коду (програмісти вони ліниві). ++ - означає "взяти теперішне значення, а після цього збільшити його на одиницю)

Давайте перепишемо код кодізі, щоб прибрати цей цукор:

{
  big[bigIndex++] = myArray[i];
}

це те саме що

{
  big[bigIndex] = myArray[i];
  bigIndex = bigIndex + 1;
}

і саме такий код ви й написали (що є абсолютно вірним)

2 Likes

Одна з причин створення методів - прибирання дуплікації коду. В данній задачі, нам треба перетворити масив в строку два рази, тому кодізі вирішив виділити для цього метод.

Ми знаємо, що масив, який нам треба перетворити може бути не повністю заповнений. Саме тому, метод також приймає “справжній розмір” (actualSize).

В найгіршому випадку, масив може бути абсолютно пустим, тому ми перевіряємо actualSize > 0 і якщо ця умова не виконується, ми повертаємо пусту строку.

В разі якщо масив не пустий, ми знаємо що ми хочемо мати формат значення-пробіл-значення. В самому кінці ми не хочемо ставити пробіл.

Таким чином, ми проходимо від першого до передостаннього справжнього значення і дописуємо в строку, що ми хочемо повернути.

На першому кроці буде "101 ".
На другому кроці буде "101 756 ".
Після цього ми виходимо з циклу, адже 756 це вже передостаннє число.

і в самому кінці, ми знаємо що ми хочемо дописати останнє справжнє число, але на цей раз без пробілу, і в кінці буде “101 756 255”, що ми й повернемо.

3 Likes

О! Супер! Тепер все встало на місця. Я була впевнена, що розмір масиву - це змінна величина і його можна збільшувати чи зменшувати, що власне і стало причиною всіх помилок. Також для мене відкриття, що розмір масиву може бути більшим за фактичну кількість елементів в ньому :astonished: Рада що задала це питання! Ваш приклад з картоплею - це щось! :relieved: Дуже-дуже дякую за вичерпну відповідь

3 Likes

Намагаюсь зрозуміти попереднє пояснення. Що означає чи як це написати “Ми знаємо, що масив, який нам треба перетворити може бути не повністю заповнений. Саме тому, метод також приймає “справжній розмір” (actualSize).”? як можна пояснити в коді, який це “справжній розмір”?

У коді Олени actualSize масиву це:

  • усього початкового массиву: myArray.Length
  • массиву big: bigIndex
  • массиву little: littleIndex

бо змінні bigIndex littleIndex зростають на одиничку щоразу як ми дописуємо елемент і відповідно їх кінцеве значення відповідатиме актуальному розміру масивів після виходу з першого for loop