我有以下代码:
private void AddMissingValue(ref string[] someArray) {
string mightbemissing="Another Value";
if (!someArray.Contains(mightbemissing)) {
var lst=someArray.ToList();
lst.Add(mightbemissing);
someArray=lst.ToArray();
}
}
虽然这有效(如果遗失的话,将一个项目添加到数组中),我想知道这是否可以以更智能的方式完成?我不喜欢将数组转换两次并为这么简单的任务编写这么多行。
有更好的方法吗?也许使用LinQ?
答案 0 :(得分:7)
一般的想法是正确的 - 数组是固定大小的集合,如果不重新创建数组,则无法向其添加项目。
您可以使用LINQ .Concat
方法以更优雅的方式编写您的方法,而无需创建List
:
private void AddMissingValue(ref string[] someArray)
{
string mightbemissing = "Another Value";
if (!someArray.Contains(mightbemissing))
{
someArray = someArray.Concat(new[] { mightbemissing }).ToArray();
}
}
此实现需要N * 2
次操作,这比N * 3
更好,但它仍然会多次枚举,并且在向数组添加N个项目时是二次方的。
如果您要经常执行此操作,那么更改代码以使用动态大小集合(f.i.,List
)将是一种更有效的方法。
即使您决定继续使用数组,如果您返回修改后的数组而不是使用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);
我想到的另一个实现,就性能而言是最好的(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();
使用yield
的此实现用于防止多次枚举。
如果你需要添加多个项目,那么它甚至可以通过这种方式重写,而且它似乎仍然是线性的:
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
答案 1 :(得分:2)
您必须调整数组,请参阅
https://msdn.microsoft.com/en-us/library/bb348051(v=vs.110).aspx
了解详情。实现:
// 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;
}
}
在您当前的实施中,您复制了所有项目两次,如果数组大
,这可能是不需要的...
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
然而,更好的设计是从固定大小的数组string[]
切换到List<string>
:
List<string> someList = ...
if (!someList.Contains(mightbemissing))
someList.Add(mightbemissing); // <- just Add
如果所有值都不是null
且唯一,您可以进一步改进:
HashSet<string> someHash = ...
someHash.Add(mightbemissing);