Как проверить, что элемент массива удовлетворяет условию?

Рейтинг: 0Ответов: 1Опубликовано: 05.07.2023

У меня есть задание:

Implement an FilterByDigit method that obtains an array of integers whose elements contain a given digit. Don't use LINQ. The task definition is given in the XML-comments for this method. For example, for array { 1, 2, 3, 4, 5, 6, 7, 68, 69, 70, 15, 17 } => { 7, 70, 17 } for digit = 7.
Topics - arrays, arithmetic operations.

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

Вот мой код, который я написал, как его можно улучшить?

Может быть я могу использовать Array.FindAll?

namespace FilterTask
{
    public static class ArrayExtension
    {
        public static bool IsContainDigit(int element, int digit)
        {
            if (element == 0 && digit == 0)
            {
                return true;
            }

            element = Math.Abs(element);
            while (element != 0)
            {
                if (digit == element % 10)
                {
                    return true;
                }

                element /= 10;
            }

            return false;
        }

        public static int[] FilterByDigit(int[]? source, int digit)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            if (source.Length == 0)
            {
                throw new ArgumentException("Invalid size");
            }

            if (digit < 0 || digit > 9)
            {
                throw new ArgumentOutOfRangeException(nameof(digit));
            }

            int count = 0;
            for (int i = 0; i < source.Length; ++i)
            {
                if (IsContainDigit(source[i], digit))
                {
                    ++count;
                }
            }

            int[] answer = new int[count];
            int j = 0;
            for (int i = 0; i < source.Length; ++i)
            {
                if (IsContainDigit(source[i], digit))
                {
                    answer[j++] = source[i];
                }
            }

            return answer;
        }
    }
}

Ответы

▲ 1Принят

Код в целом хороший.

Для начала, можно немножко упростить поиск цифры. Поменяю названия элементов там, где считаю нужным.

private static bool ContainsDigit(int number, int digit)
{
    if (number == digit)
    {
        return true;
    }

    number = Math.Abs(number); // а надо ли это?
    while (number != 0)
    {
        if (digit == number % 10)
        {
            return true;
        }

        number /= 10;
    }

    return false;
}

Здесь для производительности ещё можно Math.DivRem прикрутить, но не буду усложнять.

Далее, у вас двойной проход. Из условия не ясно, можно ли модифицировать исходный массив. Допустим, можно.

Уберу обработку исключений для простоты ответа.

public static int[] FilterByDigit(int[] source, int digit)
{
    int j = 0;
    for (int i = 0; i < source.Length; ++i)
    {
        int number = source[i];
        if (ContainsDigit(number, digit) && j != i)
        {
            source[j++] = number;
        }
    }
    Array.Resize(ref source, j);
    return source;
}

Итого, с использованием ровно такого же объёма памяти, но в 2 раза быстрее.

Если исходный массив модифицировать нельзя, то придётся сделать копию, например с помощью Array.Copy. А можете или нет использовать FindAll - вам решать, ну или тому, кто дал вам эту задачу.