A more convenient way to add a new value to a 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 is working (add an element to the array if not present), I wonder if this can be done in a smarter way? I don't like to convert the array twice and write so many lines for such a simple task.

Is there a better way? Perhaps using LinQ?

+3


source to share


2 answers


The general idea is right - an array is a fixed size and you cannot add an element to it without re-creating the array.

Your method could be written in a slightly more elegant way using a LINQ method .Concat

without being instantiated List

:

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

      

This implementation does N * 2

better operations than yours N * 3

, but it still enumerates it multiple times and is quadratic for adding N elements to your array.
If you are going to perform this operation too often, then it is more efficient to change your code to use dynamic-sized collections (fi, List

).

Even if you decide to continue using arrays, it will probably (imo) look better if you return the modified array instead ref

:

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 most efficient

Another implementation that comes to my mind and is the best ( O(N)

) in terms of performance (not for dynamically sized collections, but for previous solutions) and has the LINQ style:

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 c implementation is yield

used to prevent multiple enumeration.

If you need to add multiple elements, then it can even be rewritten this way and it still seems 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

      

+7


source


You have to resize the array, see

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 your current implementation, you are copying all elements twice , which might not be desired 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 

      

However, the best option is to go from a fixed-size array string[]

to, say List<string>

:

  List<string> someList = ...

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

      

if all values ​​are supposed to be non null

-unique, you can make a further improvement:

  HashSet<string> someHash = ...

  someHash.Add(mightbemissing); 

      

+2


source







All Articles