我有一个整数列表:
List<int> foo = new List<int>() {1, 2, 3, 4, 5, 6, 7, 8};
我需要根据索引的奇偶性对它进行切片,所以:
List<int> bar1 = foo.Where((i, v) => v % 2 == 0).ToList();
List<int> bar2 = foo.Where((i, v) => v % 2 == 1).ToList();
问题是,如果我现在设置
bar1[0] = -1
原始的 foo 列表保持不变。 有什么变通办法可以更改 bar1 和 bar2 的值,同时还可以更改原始 foo 列表的值?>
答案 0 :(得分:2)
要保持所需的格式,我不建议您使用引用类型的对象来填充集合,例如,这将起作用
public class ReferenceInt
{
public int Value { get; set; } = 0;
}
现在这可以工作:
List<ReferenceInt> foo = new List<ReferenceInt>()
{
new ReferenceInt(){ Value = 1 },
new ReferenceInt(){ Value = 2 },
new ReferenceInt(){ Value = 3 },
new ReferenceInt(){ Value = 4 },
new ReferenceInt(){ Value = 5 },
new ReferenceInt(){ Value = 6 },
new ReferenceInt(){ Value = 7 },
new ReferenceInt(){ Value = 8 }
};
现在您必须过滤参考对象内的每个值
List<ReferenceInt> bar1 = foo.Where(v => v.Value % 2 == 0).ToList();
List<ReferenceInt> bar2 = foo.Where(v => v.Value % 2 == 1).ToList();
,这更改了其中所有带有ReferenceInt
的集合中的值。
所以foo
和bar1
都将显示相同的内容
bar1[1].Value = 17;
答案 1 :(得分:2)
您可以创建代理以在源列表和过滤视图之间工作。
public class Indexer<T> : IEnumerable<T>
{
public T this[int index]
{
get => All().ElementAt(index);
set
{
var i = 0;
foreach (var item in _source)
if (_filter(item))
{
if (i++ == index)
_source[i] = value;
break;
}
}
}
public IEnumerable<T> All() => _source.Where(o => _filter(o));
readonly IList<T> _source;
readonly Func<T, bool> _filter;
public Indexer(IList<T> source, Func<T, bool> filter)
{
_source = source;
_filter = filter;
}
IEnumerator<T> IEnumerable<T>.GetEnumerator() => All().GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => All().GetEnumerator();
}
此代理将谨慎处理索引并简化用法:
List<int> foo = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 };
var bar1 = new Indexer<int>(foo, o => o % 2 == 0);
Console.WriteLine(string.Join(",", bar1)); // 2,4,6,8
bar1[0] = -1;
Console.WriteLine(string.Join(",", bar1)); // 4,6,8
Console.WriteLine(string.Join(",", foo)); // 1,-1,3,4,5,6,7,8