我有一个很大的列表,如果需要,我想覆盖一个值。为此,我创建了列表的两个子集,似乎给了我OutOfMemoryException
。这是我的代码片段:
if (ownRG != "")
{
List<string> maclist = ownRG.Split(',').ToList();
List<IVFile> temp = powlist.Where(a => maclist.Contains(a.Machine)).ToList();
powlist = powlist.Where(a => !maclist.Contains(a.Machine)).ToList(); // OOME Here
temp.ForEach(a => { a.ReportingGroup = ownRG; });
powlist.AddRange(temp);
}
基本上我将列表分成需要更新的部分和不需要更新的部分,然后我执行更新并将列表重新组合在一起。这适用于较小的列表,但在OutOfMemoryException
的第三行中为if
打破一个大列表。我可以提高效率吗?
注意
powlist
是大型列表(&gt; 1m)。 maclist
只有1到10之间,但即使有1个项目也会中断。
答案 0 :(得分:2)
以下是如何使用我的答案中的枚举器代码重新排列代码:
if (!string.IsNullOrEmpty(ownRG))
{
var maclist = new CommaSeparatedStringEnumerable(str);
var temp = powlist.Where(a => maclist.Contains(a.Machine));
foreach (var p in temp)
{
p.ReportingGroup = ownRG;
}
}
ToList
。temp
中移除powlist
的内容(无论如何,您正在重新添加它们)您可以通过查找,
字符并记住上次找到的字符和之前的字符的位置,手动迭代列表而不是执行您现在所做的操作。这肯定会使你的应用程序工作,因为它不需要立即将整个集合存储在内存中。
代码示例:
var str = "aaa,bbb,ccc";
var previousComma = -1;
var currentComma = 0;
for (; (currentComma = str.IndexOf(',', previousComma + 1)) != -1; previousComma = currentComma)
{
var currentItem = str.Substring(previousComma + 1, currentComma - previousComma - 1);
Console.WriteLine(currentItem);
}
var lastItem = str.Substring(previousComma + 1);
Console.WriteLine(lastItem);
如果你想以一种奇特的方式'正确',你甚至可以写一个自定义的枚举器:
public class CommaSeparatedStringEnumerator : IEnumerator<string>
{
int previousComma = -1;
int currentComma = -1;
string bigString = null;
bool atEnd = false;
public CommaSeparatedStringEnumerator(string s)
{
if (s == null)
throw new ArgumentNullException("s");
bigString = s;
this.Reset();
}
public string Current { get; private set; }
public void Dispose() { /* No need to do anything here */ }
object IEnumerator.Current { get { return this.Current; } }
public bool MoveNext()
{
if (atEnd)
return false;
atEnd = (currentComma = bigString.IndexOf(',', previousComma + 1)) == -1;
if (!atEnd)
Current = bigString.Substring(previousComma + 1, currentComma - previousComma - 1);
else
Current = bigString.Substring(previousComma + 1);
previousComma = currentComma;
return true;
}
public void Reset()
{
previousComma = -1;
currentComma = -1;
atEnd = false;
this.Current = null;
}
}
public class CommaSeparatedStringEnumerable : IEnumerable<string>
{
string bigString = null;
public CommaSeparatedStringEnumerable(string s)
{
if (s == null)
throw new ArgumentNullException("s");
bigString = s;
}
public IEnumerator<string> GetEnumerator()
{
return new CommaSeparatedStringEnumerator(bigString);
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
然后你可以像这样迭代它:
var str = "aaa,bbb,ccc";
var enumerable = new CommaSeparatedStringEnumerable(str);
foreach (var item in enumerable)
{
Console.WriteLine(item);
}
我可以提高效率吗?
是的,你可以。我建议使用更高效的数据格式(您可以根据需要查看数据库或XML,JSON等)。如果您真的想使用以逗号分隔的项目,请参阅上面的代码示例。
答案 1 :(得分:1)
在循环中找到下一个','char。取','和前一个','位置之间的子串。在循环结束时保存对前一个','位置的引用(最初设置为0)。因此,您逐个解析项目而不是一次解析所有项目。
答案 2 :(得分:1)
无需从powlist
创建一堆子列表并重新构建它。只需循环遍历powlist
并相应地更新ReportingGroup
属性。
var maclist = new HashSet<string>( ownRG.Split(',') );
foreach( var item in powlist) {
if( maclist.Contains( item.Machine ) ){
item.ReportingGroup = ownRG;
}
}
由于这会更改powlist
,因此您不会分配任何额外的内存,也不应该遇到OutOfMemoryException
。
答案 3 :(得分:-2)
您可以尝试循环列表中的项目,但这会增加处理时间。
foreach(var item in powlist)
{
//do your opeartions
}