Каков самый короткий способ инициализации строкового массива с пустыми строками?

Удивительно для меня

new string[count];

заполняется null s. Поэтому я придумал

var emptyStrings = Enumerable.Range(0, count)
    .Select(a => String.Empty)
    .ToArray();

который очень многословен. Разве нет обрезки?

Ответ 1

Вы можете использовать Enumerable.Repeat:

 string[] strings = Enumerable.Repeat(string.Empty, count).ToArray();

(Но имейте в виду, что создание массива строк с правильным размером и циклом даст лучшую производительность.)

Ответ 2

Обработка нескольких измерений

Мне пришлось работать с множеством строковых массивов, которые нужно было инициализировать до пустых, некоторые многомерные. Это было немного больно, поэтому я создал следующее, которое вы можете найти полезным:

public static class StringArrayExtensions
{
    public static string[] InitializeWithEmptyStrings(this string[] source)
    {
        // the jitter will hoist source.Length out of the loop automatically here
        for(int i = 0; i < source.Length; i++)
            source[i] = string.Empty;

        return source;          
    }

    public static string[,] InitializeWithEmptyStrings(this string[,] source)
    {
        var len0 = source.GetLength(0);
        var len1 = source.GetLength(1);
        for (int i = 0; i < len0; i++)
            for (int j = 0; j < len1; j++)
                source[i,j] = string.Empty;

        return source;
    }
}

Затем вы можете сделать что-то вроде:

class Foo
{
    public string[,] Data = new string[2,2].InitializeWithEmptyStrings();
}

Обновление - один способ обработки произвольных измерений

Я подумал, что было бы интересно попробовать и обобщить это, чтобы объединить создание массива и его инициализацию с использованием метода общего назначения. Это будет не так быстро, как указано выше, но оно будет обрабатывать произвольное количество измерений:

public static class ArrayFactory
{
    public static TArrayType CreateArrayInitializedWithEmptyStrings<TArrayType>(
        params int[] dimensionLengths) where TArrayType : class
    {
        var dimensions = dimensionLengths.Select(l => Enumerable.Range(0, l));
        var array = Array.CreateInstance(typeof(string), dimensionLengths);
        foreach (var indices in CartesianProduct(dimensions))
            array.SetValue(string.Empty, indices.ToArray());

        return (array as TArrayType);
    }

    private static IEnumerable<IEnumerable<T>> CartesianProduct<T>(
    IEnumerable<IEnumerable<T>> dimensions)
    {
        return dimensions.Aggregate(
            (IEnumerable<IEnumerable<T>>)new T[][] { new T[0] },
            (acc, input) =>
                from prevDimension in acc
                from item in input
                select prevDimension.Concat(new T[] { item }));
    }
}

Этот метод требует требуемого массива в качестве общего параметра - используйте так:

// this would create a string[2,3,4,2] initialized with empty strings
ArrayFactory.CreateArrayInitializedWithEmptyStrings<string[,,,]>(2,3,4,2);

Подкрепляет Ян Гриффитса для своей статьи серии статей, которая была источником обобщенного метода CartesianProduct.

Обновление 2

Здесь уточненная версия декартова продукта, использующая рекурсию для получения индексных комбинаций:

public static class ArrayFactory
{
    public static TArrayType CreateArrayInitializedWithEmptyStrings<TArrayType>(
            params int[] dimensionLengths) where TArrayType : class
    {
        var array = Array.CreateInstance(typeof(string), dimensionLengths);
        foreach (var indices in CartesianProduct(dimensionLengths))
            array.SetValue(string.Empty, indices.ToArray());

        return (array as TArrayType);
    }

    private static IEnumerable<IEnumerable<int>> CartesianProduct(params int[] dimensions)
    {
        return CartesianProductImpl(Enumerable.Empty<int>(), dimensions);

        IEnumerable<IEnumerable<int>> CartesianProductImpl(
            IEnumerable<int> leftIndices, params int[] dims)
        {
            if (dims.Length == 0)
            {
                yield return leftIndices;
                yield break;
            }

            for (int i = 0; i < dims[0]; i++)
                foreach (var elem in CartesianProductImpl(leftIndices.Concat(new[] { i }),
                         dims.Skip(1).ToArray()))
                    yield return elem;
        }
    }
}