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?
source to share
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
source to share
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);
source to share