如何使用LINQ(en masse)

时间:2016-08-26 16:57:26

标签: c# arrays linq

我有一个(类)类型Foo的数组或集合,其属性Value的类型为double。如果我有一个值列表,如何使用LINQ将它们分配给我的集合。

基本上我想要反过来

var values = list.Select((item)=>item.Value).ToArray();

示例代码:

class Foo
{
    public double Value { get; set; }
    // many other properties
}

static void Main() 
{
    // example initializations
    var list = new Foo[4];

    // somewhere else in the code
    var values = GetValues();
    // returns { 10.0, 12.0, 15.5, 17.3 }

    // Q? Can I do this in LINQ with one statement,
    // without re-creating list. I just want to set
    // one property of Foo based on my array.

    // assign values (I know lengths will match)
    for(int i=0; i<list.Length; i++)
    {
        list[i].Value = values[i];
    }

}

我试过这个(并且失败了):

list.Zip(values, (leg, val) => leg.Value=val );

但这有效,虽然它感觉像是一个kludge

list.Zip(values, (leg, val) => leg.Value=val ).ToArray();

PS。这类似于assign value using linq,除了我想要分配列表中的所有值,而不只是过滤一个并获得对它的引用。

PS2。如果Foo是值类型,那会更难。

FYI。在Fortran中,即使list%value = values是一个数组,也会list。在Fortran中,结构数组也等同于数组结构。我希望其他语言(Python,Julia?)也做同样的事情。 C类型的语言不是: - (

4 个答案:

答案 0 :(得分:3)

很好,您使用Zip将要更新的项目与要注入的值配对,但这就是您应该做的所有事情接着就,随即。一旦你配对它们,你应该遍历对来进行更新。

var pairs = list.Zip(values, (leg, val) => new { leg, val });
foreach (var pair in pairs)
    pair.leg.Value = pair.val;

Linq旨在帮助您查询数据,而不是对其进行修改。

答案 1 :(得分:0)

您可以创建类似LINQ的扩展方法,这不会返回IEnumerable,但会修改传入的IEnumerable(或IList结构)。

public static class ExtentionMethods
{
    public static void Update<TItem, TValue>(this IEnumerable<TItem> @this, IEnumerable<TValue> items, Action<TItem, TValue> applyAction) 
        where TItem : class
    {
        using (var thisEnumerator = @this.GetEnumerator())
        using (var itemEnumerator = items.GetEnumerator())
        {
            while (thisEnumerator.MoveNext() && itemEnumerator.MoveNext())
            {
                applyAction(thisEnumerator.Current, itemEnumerator.Current);
            }
        }
    }

    public delegate void UpdateAction<TItem, TValue>(ref TItem item, TValue newValue);

    public static void Update<TItem, TValue>(this IList<TItem> @this, IEnumerable<TValue> items, UpdateAction<TItem, TValue> applyAction)
where TItem : struct 
    {

        using (var itemEnumerator = items.GetEnumerator())
        {
            for (int i = 0; i < @this.Count && itemEnumerator.MoveNext(); i++)
            {
                var temp = @this[i];
                applyAction(ref temp, itemEnumerator.Current);
                @this[i] = temp;
            }
        }
    }
}

一样使用
namespace SandboxConsole
{
    class Program
    {
        class Foo
        {
            public double Value { get; set; }
        }
        struct Foo2
        {
            public double Value { get; set; }
        }

        private static IReadOnlyList<double> GetValues()
        {
            return new[] { 10.0, 12.0, 15.5, 17.3 };
        }

        static void Main()
        {
            // example initializations
            var list = new Foo[4];
            var list2 = new Foo2[4];

            // somewhere else in the code
            var values = GetValues();
            // returns { 10.0, 12.0, 15.5, 17.3 }

            list.Update(values, (item, value) => item.Value = value);
            list2.Update(values, (ref Foo2 item, double value) => item.Value = value);
        }
    }
}

答案 2 :(得分:-2)

此:

var list = values.Select(item =>new Foo{Value=item}).ToArray();

同样:

for(int i=0; i<list.Length; i++)
{
  list[i].Value = values[i];
}

答案 3 :(得分:-3)

您可以在列表中使用ForEach

class Program
{
    static void Main(string[] args)
    {
        int[] x = { 1, 2, 3 };
        Foo[] y = new Foo[]{ new Foo{Name="a"},new Foo{Name="b"},new Foo{Name="c"}};

        int i = 0;
        y.ToList().ForEach(a => a.Value = x[i++]);

        foreach (Foo f in y) 
          Console.Out.WriteLine(f.ToString());

        //or even ;)
        y.ToList().ForEach(a => Console.Out.WriteLine(a.ToString));
    }
}
class Foo
{
    public int Value { get; set; }
    public string Name { get; set; }
    public override string ToString()
    {
        return Name + Value;
    }
}

我想不出现在放弃int i = 0行的方法

但如果你这样做,请考虑https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/中提出的论点?

编辑:好的,所以有人认为它不是LINQ(ToList()是)。这样做:

class Program
{
    static void Main(string[] args)
    {
        int[] x = { 1, 2, 3 };
        Foo[] y = new Foo[]{ new Foo{Name="a"},new Foo{Name="b"},new Foo{Name="c"}};

        int i = 0;
        y.Select(a => a.Value = x[i++]).ToArray();

        foreach (Foo f in y) 
          Console.Out.WriteLine(f.ToString());
    }
}
class Foo
{
    public int Value { get; set; }
    public string Name { get; set; }
    public override string ToString()
    {
        return Name + Value;
    }
}

Select是LINQ,ToArray在循环打印值时实际发生了动作..虽然这不是查询系统的预期目的

高而缺乏:

问:“我怎么......”

答:你没有

答:你使用fortran

答:你编写一个foreach循环,就像其他任何有兴趣生成可读,自解释,可维护代码的人一样