Удивительно для меня
new string[count];
заполняется null
s. Поэтому я придумал
var emptyStrings = Enumerable.Range(0, count)
.Select(a => String.Empty)
.ToArray();
который очень многословен. Разве нет обрезки?
Удивительно для меня
new string[count];
заполняется null
s. Поэтому я придумал
var emptyStrings = Enumerable.Range(0, count)
.Select(a => String.Empty)
.ToArray();
который очень многословен. Разве нет обрезки?
Вы можете использовать Enumerable.Repeat
:
string[] strings = Enumerable.Repeat(string.Empty, count).ToArray();
(Но имейте в виду, что создание массива строк с правильным размером и циклом даст лучшую производительность.)
Мне пришлось работать с множеством строковых массивов, которые нужно было инициализировать до пустых, некоторые многомерные. Это было немного больно, поэтому я создал следующее, которое вы можете найти полезным:
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.
Здесь уточненная версия декартова продукта, использующая рекурсию для получения индексных комбинаций:
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;
}
}
}