简体   繁体   English

为字符串数组添加新值的更好方法?

[英]A nicer way to add a new value to string array?

I have the following code: 我有以下代码:

private void AddMissingValue(ref string[] someArray) {
  string mightbemissing="Another Value";
  if (!someArray.Contains(mightbemissing)) {
    var lst=someArray.ToList();
    lst.Add(mightbemissing);
    someArray=lst.ToArray();
  }
}

While this works (Add an item to an array if missing), I wonder if this can be done in a smarter way? 虽然这有效(如果遗失的话,将一个项目添加到数组中),我想知道这是否可以以更智能的方式完成? I don't like converting the array twice and writing so many lines for such a simple task. 我不喜欢将数组转换两次并为这么简单的任务编写这么多行。

Is there a better way? 有没有更好的办法? Maybe using LinQ? 也许使用LinQ?

General idea is right - array is a fixed-sized collection and you cannot add an item to it without recreating an array. 一般的想法是正确的 - 数组是一个固定大小的集合,你不能在不重新创建数组的情况下向其添加项目。

Your method can be written in a slightly more elegant way using LINQ .Concat method without creating a List : 您可以使用LINQ .Concat方法以更优雅的方式编写您的方法,而无需创建List

private void AddMissingValue(ref string[] someArray)
{
    string mightbemissing = "Another Value";
    if (!someArray.Contains(mightbemissing))
    { 
        someArray = someArray.Concat(new[] { mightbemissing }).ToArray();
    }
}

This implementation takes N * 2 operations which is better than your N * 3 , but it is still enumerating it multiple times and is quadratic for adding N items to your array. 这个实现需要N * 2操作,这个操作比你的N * 3要好,但是它仍然会多次枚举,并且在你的数组中添加N个项目是二次的。
If you are going to perform this operation too often, then changing your code to use dynamic-size collections (fi, List ) would be a more effective way. 如果您要经常执行此操作,那么更改代码以使用动态大小集合(fi, List )将是一种更有效的方法。

Even if you decide to continue using arrays, it probably (imo) will look better if you return modified array instead of using ref : 即使你决定继续使用数组,如果你返回修改后的数组而不是使用ref ,它可能会(imo)看起来更好:

private string[] AddMissingValue(string[] someArray)
{
    string mightbemissing = "Another Value";
    return someArray.Contains(mightbemissing)
        ? someArray
        : someArray.Concat(new[] { mightbemissing }).ToArray();
}

// Example usage:

string[] yourInputArray = ...;
yourInputArray = AddMissingValue(yourInputArray);

LINQ-style and the most performant LINQ风格和最高性能

Another implementation which comes to my mind and is the best ( O(N) ) in terms of performance (not against dynamic-size collections, but against previous solutions) and is LINQ-styled: 我想到的另一个实现是性能方面最好的( O(N) )(不是针对动态大小的集合,而是针对以前的解决方案)并且是LINQ风格的:

public static class CollectionExtensions
{
    public static IEnumerable<T> AddIfNotExists<T>(this IEnumerable<T> enumerable, T value) 
    {
        bool itemExists = false;
        foreach (var item in enumerable)
        {
            if (!itemExists && value.Equals(item))
                itemExists = true;

            yield return item;
        }

        if (!itemExists)
            yield return value;
    }
}

// Example usage:
string[] arr = ...;
arr = arr.AddIfNotExists("Another Value").ToArray();

This implementation with yield is used to prevent multiple enumeration. 带有yield此实现用于防止多次枚举。

If you need to add multiple items, then it can even be rewritten this way, and it seems to still be linear: 如果你需要添加多个项目,那么它甚至可以通过这种方式重写,它似乎仍然是线性的:

public static IEnumerable<T> AddIfNotExists<T>(this IEnumerable<T> enumerable, params T[] value) 
{
    HashSet<T> notExistentItems = new HashSet<T>(value);
    foreach (var item in enumerable)
    {
        if (notExistentItems.Contains(item))
            notExistentItems.Remove(item);

        yield return item;
    }

    foreach (var notExistentItem in notExistentItems)
        yield return notExistentItem;
}

// Usage example:
int[] arr = new[] { 1, 2, 3 };
arr = arr.AddIfNotExists(2, 3, 4, 5).ToArray(); // 1, 2, 3, 4, 5

You have to resize the array, see 您必须调整阵列的大小 ,请参阅

https://msdn.microsoft.com/en-us/library/bb348051(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/bb348051(v=vs.110).aspx

for details. 详情。 Implementation: 执行:

// static: it seems that you don't want "this" in the method
private static void AddMissingValue(ref string[] someArray) {
  string mightbemissing = "Another Value";

  if (!someArray.Contains(mightbemissing)) {
    Array.Resize(ref someArray, someArray.Length + 1);

    someArray[someArray.Length - 1] = mightbemissing;
  }
}

In you current implementation, you copy all the items twice which can be unwanted if the array is large 在当前实现中,您将所有项目复制两次 ,如果数组很大 ,则可能不需要这些项目

...
var lst=someArray.ToList(); // first: all data copied from array to list
lst.Add(mightbemissing);
someArray=lst.ToArray();    // second: all data copied from list to array 

A better design, however, is to switch from fixed size array string[] to, say, List<string> : 然而,更好的设计是从固定大小的数组string[]切换到,例如, List<string>

  List<string> someList = ...

  if (!someList.Contains(mightbemissing))
    someList.Add(mightbemissing); // <- just Add

if all the values should be not null and unique you can do further improvement: 如果所有值都不为null唯一 ,则可以进一步改进:

  HashSet<string> someHash = ...

  someHash.Add(mightbemissing); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM