假设我有一个List<MyClass> myObjects
,而我有int[] numbers
。鉴于:
numbers
的长度等于mObjects.Count
。我正在使用的类具有其他一些字段和方法,如下所示:
class MyClass
{
public int Number;
public int AnotherNumber;
public void WorkWithNumber() { /* Do some work. */ }
}
是否可以使用linq将numbers
的每个项目分配给列表中相应的MyClass.Number
?最好使用myObjects.ForEach()
。
答案 0 :(得分:1)
理想情况下,您应该使用foreach
循环:
foreach (var p in myList.Select((obj, idx) => new { Val = numbers[idx], Obj = obj })) {
p.Obj.Number = p.Val;
}
您可以在没有foreach
的情况下使用相同的技巧,但是解决方案的可读性会大大降低。
答案 1 :(得分:1)
用于在两个列表上同步迭代的LINQ算法为 Enumerable.Zip
。
但是除非您对表达式的结果求值,否则这是行不通的,因为
您可以通过应用.ToList()
来避免这种陷阱并丢弃结果:
numbers.Zip(myObjects, (i, obj) => obj.Number = i).ToList();
但这不是那么漂亮。
另一种选择是添加非功能性重载.Zip
。即:
public static class EnumerableX
{ public static void Zip<T1,T2>(this IEnumerable<T1> list1, IEnumerable<T2> list2, Action<T1,T2> act)
{ using (var en1 = list1.GetEnumerator())
using (var en2 = list2.GetEnumerator())
while (en1.MoveNext() & en2.MoveNext())
act(en1.Current, en2.Current);
}
}
使用此扩展名以下行将完成工作:
numbers.Zip(myObjects, (i, obj) => { obj.Number = i; });
但是值类型的问题仍然存在。为了克服这个问题,Action
的参数需要为ref T1
类型。但这显然需要更多工作,并且不在这个问题的范围内。
答案 2 :(得分:0)
我将在myObjects
上使用for循环,并从Number
中的相应索引中分配numbers
属性。
void Main()
{
var myObjects = new List<MyClass>();
myObjects.Add(new MyClass());
myObjects.Add(new MyClass());
myObjects.Add(new MyClass());
var numbers = new int[] { 1, 2, 3 };
for(var i = 0; i < myObjects.Count; i++)
{
myObjects.ElementAt(i).Number = numbers[i];
Console.WriteLine($"myObjects.ElementAt(i).Number = {myObjects.ElementAt(i).Number}");
}
// myObjects.ElementAt(i).Number = 1
// myObjects.ElementAt(i).Number = 2
// myObjects.ElementAt(i).Number = 3
}
class MyClass
{
public int Number;
public int AnotherNumber;
public void WorkWithNumber() { /* Do some work. */ }
}
答案 3 :(得分:0)
如果您真的想使用LINQ,则Select的重载将带有两个参数的lambda:object及其索引:
public class Program
{
public static void Main(string[] args)
{
var list = new []{1,2,3,4,5};
var objects = new []{new Obj(),new Obj(),new Obj(),new Obj(),new Obj()};
objects = objects.Select((x,i)=>{
x.Int = list[i];
return x;
}).ToArray();
foreach(var o in objects)
{
Console.WriteLine(o.Int);
}
}
}
public class Obj
{
public int Int {get;set;}
}
您需要调用ToArray()以便对LINQ进行评估,但是不必将其归还给对象变量
答案 4 :(得分:0)
如果您想以简单的方式限制ForEach
,可以尝试一下。
List<MyClass> myObjects = new List<MyClass>();
myObjects.Add(new MyClass());
myObjects.Add(new MyClass());
myObjects.Add(new MyClass());
int[] numbers = new int[] { 1, 2, 3 };
int i = 0;
myObjects.ForEach(x =>
{
x.Number = numbers[i];
i++;
});
答案 5 :(得分:0)
这是您想要的吗?
//Set things up...
List<MyClass> myObjects = new List<MyClass>
{
new MyClass{Number = 23},
new MyClass{Number = 42},
new MyClass{Number = 66}
};
int [] numbers = new int[myObjects.Count];
//answer your question...
var i = 0;
foreach (var myObj in myObjects)
{
numbers[i] = myObj.Number;
++i;
}
您可以使用“ for”遍历两个集合,但是“ foreach”仅适用于单个集合(除非有我不知道的语言功能)。
答案 6 :(得分:0)
您可以利用overload to Select
为您传递索引:
numbers.Select((item, index) => myObjects[index].Number = item)
.ToList();
此方法的缺点在于,您需要调用ToList/ToArray
来强制执行Select
的开销。您可以编写自己的扩展方法来迭代可枚举,但不执行任何操作:
public static class MyEnumerableExtensions
{
public static void ForceExecute<T>(this IEnumerable<T> source)
{
foreach (T item in source);
}
}
...然后:
numbers.Select((item, index) => myObjects[index].Number = item)
.ForceExecute();
...尽管这样做对您的程序员来说可能不那么直观。