What is the shortest way to init a string array with empty strings?
Surprisingly for me
new string[count];
is filled with null
s. So I came up with
var emptyStrings = Enumerable.Range(0, count)
.Select(a => String.Empty)
.ToArray();
which is very verbose. Isn't there a sho开发者_运维问答rcut?
You can use Enumerable.Repeat
:
string[] strings = Enumerable.Repeat(string.Empty, count).ToArray();
(But be aware that creating a string array of the correct size and looping will give better performance.)
Handling multiple dimensions
I had to work with a bunch of string arrays that had to be initialized to empty, some multi-dimensional. This was a bit of a pain so I created the following which you may find useful:
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;
}
}
Then you can do something like:
class Foo
{
public string[,] Data = new string[2,2].InitializeWithEmptyStrings();
}
Update - One method to handle arbitrary dimensions
I thought it would be fun to try and generalise this to combine creating the array and initializing it, using a general purpose method. It's not going to be as fast as the above, but it will handle arbitrary numbers of dimensions:
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 method requires the desired array as a generic parameter - use like so:
// this would create a string[2,3,4,2] initialized with empty strings
ArrayFactory.CreateArrayInitializedWithEmptyStrings<string[,,,]>(2,3,4,2);
Props to Ian Griffiths for his article series which was the source of the generalized CartesianProduct method.
Update 2
Here's a refined version of the Cartesian Product that used recursion to get the index combinations:
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;
}
}
}
精彩评论