如何在不使用占位列表变量的情况下,最有效地删除一个List<T>
中的交替元素(奇数索引或偶数索引)?
如果您能在每个答案中提到成本,将不胜感激。
我正在寻找一种高效的方法来完成这个操作。
谢谢!
如何在不使用占位列表变量的情况下,最有效地删除一个List<T>
中的交替元素(奇数索引或偶数索引)?
如果您能在每个答案中提到成本,将不胜感激。
我正在寻找一种高效的方法来完成这个操作。
谢谢!
int pos = 0;
for (int i = 0; i < values.Count; i += 2, pos++) {
values[pos] = values[i];
}
values.RemoveRange(pos, values.Count - pos);
编辑:
使用此方法可以在15毫秒内处理100万个整数的列表。如果使用RemoveAt,则需要超过三分钟...
编辑2:
实际上,您可以从pos=1和i=2(或3)开始,因为第一个项目不必被复制到自身。但这使得代码有点不太明显。
考虑一种创建新列表的解决方案,可以使用一个旧列表 old 来实现:
var newList = old.Where((_, i) => i%2 != 0).ToList();
var newList = l.Where((_, i) => i%2 == 0).ToList();
根据你选择的替代方案而定。
编辑
答案相当快。如果你在这里读到其他内容,那是因为我在周末测量,周末的大脑很有趣。 :( 闭包解决方案约快40%,而答案要快大约2个数量级。我想这真的取决于你的列表变得有多大!
另一个选项与Frank的类似,但使用闭包。而且它比Frank的版本更快。
bool isEven = true;
var newList = list.Where(x => isEven = !isEven).ToList();
List<T> list = GetTheList();
int i = 1;
while ( i < list.Count ) {
list.RemoveAt(i);
i++;
}
public static IEnumerable<T> AlternateItems<T>(this IEnumerable<T> source)
{
while (source.Any())
{
yield return source.First();
source = source.Skip(1);
if (source.Any()) source = source.Skip(1);
}
}
for (int i=myList.length-1; i >= 0; i--)
if (i % 2 == 0)
myList.Remove(myList[i]);
显然是根据使用情况而定,但您可以拥有一个包装器IList,它将您提供的索引乘以2,并报告列表的长度为1/2(详细信息被省略)。这是O(1)。
我会使用STL容器通常使用的标准模式。 先做删除,然后再进行擦除。
这样做可以避免让习惯于查看此模式的人感到困惑。
template<typename T>
struct RemoveEven
{
RemoveEven():count(0) {}
bool operator()(T const&)
{
bool result = count%2 == 0;
count++;
return result;
}
private:
std::size_t count;
};
int main()
{
std::list<int> a;
a.erase(std::remove_if(a.begin(),a.end(),RemoveEven<int>()),a.end());
}