7

当我查询它时,我希望列表中至少有 183 个项目,但有时我的提取结果导致项目计数低于 183。我当前的修复应该在计数小于 183 的情况下填充数组。

if (extractArray.Count() < 183) {
    int arraysize= extractArray.Count();
    var tempArr = new String[183 - arraysize];
    List<string> itemsList = extractArray.ToList<string>();
    itemsList.AddRange(tempArr);
    var values = itemsList.ToArray();
    //-- Process the new array that is now at least 183 in length
}

但似乎我的解决方案不是最好的。我将不胜感激任何其他可以帮助确保我在提取时获得至少 183 个项目的解决方案。

4

4 回答 4

8

我可能会遵循其他人的建议,并使用一个列表。使用“容量”构造函数来增加性能:

var list = new List<string>(183);

然后,每当您获得一个新数组时,请执行此操作(将“”替换为您用于填充数组的任何值):

list.Clear();
list.AddRange(array);
// logically, you can do this without the if, but it saves an object allocation when the array is full
if (array.Length < 183)
    list.AddRange(Enumerable.Repeat(" ", 183 - array.Length));

这样,列表总是重用相同的内部数组,减少分配和 GC 压力。

或者,您可以使用扩展方法:

public static class ArrayExtensions
{
    public static T ElementOrDefault<T>(this T[] array, int index)
    {
        return ElementOrDefault(array, index, default(T));
    }
    public static T ElementOrDefault<T>(this T[] array, int index, T defaultValue)
    {
        return index < array.Length ? array[index] : defaultValue;
    }
}

然后这样的代码:

items.Zero = array[0];
items.One = array[1];
//...

变成这样:

items.Zero = array.ElementOrDefault(0);
items.One = array.ElementOrDefault(1);
//...

最后,这是我开始编写此答案时使用的相当麻烦的想法:您可以将数组包装在保证具有 183 个索引的 IList 实现中(为简洁起见,我省略了大多数接口成员实现):

class ConstantSizeReadOnlyArrayWrapper<T> : IList<T>
{
    private readonly T[] _array;
    private readonly int _constantSize;
    private readonly T _padValue;

    public ConstantSizeReadOnlyArrayWrapper(T[] array, int constantSize, T padValue)
    {
         //parameter validation omitted for brevity
        _array = array;
        _constantSize = constantSize;
        _padValue = padValue;
    }

    private int MissingItemCount
    {
        get { return _constantSize - _array.Length; }
    }

    public IEnumerator<T> GetEnumerator()
    {
        //maybe you don't need to implement this, or maybe just returning _array.GetEnumerator() would suffice.
        return _array.Concat(Enumerable.Repeat(_padValue, MissingItemCount)).GetEnumerator();
    }

    public int Count
    {
        get { return _constantSize; }
    }

    public bool IsReadOnly
    {
        get { return true; }
    }

    public int IndexOf(T item)
    {
        var arrayIndex = Array.IndexOf(_array, item);
        if (arrayIndex < 0 && item.Equals(_padValue))
            return _array.Length;
        return arrayIndex;
    }

    public T this[int index]
    {
        get
        {
            if (index < 0 || index >= _constantSize)
                throw new IndexOutOfRangeException();
            return index < _array.Length ? _array[index] : _padValue;
        }
        set { throw new NotSupportedException(); }
    }
}

确认。

于 2012-10-03T23:08:20.580 回答
5

Array 基类实现Resize方法

if(extractArray.Length < 183)
    Array.Resize<string>(ref extractArray, 183);

但是,请记住,调整大小会影响性能,因此此方法仅在您出于某种原因需要数组时才有用。如果您可以切换到列表

而且,我假设你这里有一个一维的字符串数组,所以我使用 Length 属性来检查数组中的有效项数。

于 2012-10-03T21:21:11.673 回答
2

由于您已声明需要确保有 183 个索引,并且如果没有,则需要填充它,因此我建议使用 List 而不是数组。您可以执行以下操作:

while (extractList.Count < 183)
{
     extractList.Add(" "); // just add a space
}

如果你绝对必须回到一个数组,你可以使用类似的东西。

于 2012-10-03T21:52:37.110 回答
2

我不能说我会推荐这个解决方案,但我不会让它阻止我发布它!不管他们是否愿意承认,每个人都喜欢 linq 解决方案!

使用 linq,给定一个包含 X 元素的数组,您可以生成一个包含恰好 Y(在您的情况下为 183 个)元素的数组,如下所示:

  var items183exactly = extractArray.Length == 183 ? extractArray :
                        extractArray.Take(183)
                                    .Concat(Enumerable.Repeat(string.Empty, Math.Max(0, 183 - extractArray.Length)))
                                    .ToArray();

如果元素少于 183 个,则将使用空字符串填充数组。如果元素超过 183 个,则数组将被截断。如果正好有 183 个元素,则按原样使用数组。

我并不是说这是有效的,也不是说它一定是个好主意。但是,它确实使用了 linq(yippee!),而且很有趣。

于 2012-10-04T17:43:15.400 回答