代码之家  ›  专栏  ›  技术社区  ›  Hugo

用C语言中的一条foreach语句迭代两个列表或数组#

c#
  •  125
  • Hugo  · 技术社区  · 15 年前

    这只是为了常识:

    如果我有两个,假设, 我想用相同的foreach循环来迭代这两个函数,可以吗?

    编辑

    为了澄清,我想这样做:

    List<String> listA = new List<string> { "string", "string" };
    List<String> listB = new List<string> { "string", "string" };
    
    for(int i = 0; i < listA.Count; i++)
        listB[i] = listA[i];
    

    但是有一个前臂=)

    11 回复  |  直到 6 年前
        1
  •  226
  •   Matt Becker    8 年前

    这被称为 Zip 操作,并将在.NET 4中受支持。

    有了它,你就可以写下:

    var numbers = new [] { 1, 2, 3, 4 };
    var words = new [] { "one", "two", "three", "four" };
    
    var numbersAndWords = numbers.Zip(words, (n, w) => new { Number = n, Word = w });
    foreach(var nw in numbersAndWords)
    {
        Console.WriteLine(nw.Number + nw.Word);
    }
    

    作为具有命名字段的匿名类型的替代方法,还可以使用元组及其静态元组保存在大括号上。创建助手:

    foreach (var nw in numbers.Zip(words, Tuple.Create)) 
    {
        Console.WriteLine(nw.Item1 + nw.Item2);
    }
    
        2
  •  13
  •   Lauren Van Sloun Sebastian Inones    6 年前

    如果不想等待.NET 4.0,可以实现自己的 Zip 方法。以下内容适用于.NET 2.0。您可以根据您希望如何处理两个枚举(或列表)具有不同长度的情况来调整实现;这一个继续到较长枚举的结尾,返回较短枚举中缺少项的默认值。

    static IEnumerable<KeyValuePair<T, U>> Zip<T, U>(IEnumerable<T> first, IEnumerable<U> second)
    {
        IEnumerator<T> firstEnumerator = first.GetEnumerator();
        IEnumerator<U> secondEnumerator = second.GetEnumerator();
    
        while (firstEnumerator.MoveNext())
        {
            if (secondEnumerator.MoveNext())
            {
                yield return new KeyValuePair<T, U>(firstEnumerator.Current, secondEnumerator.Current);
            }
            else
            {
                yield return new KeyValuePair<T, U>(firstEnumerator.Current, default(U));
            }
        }
        while (secondEnumerator.MoveNext())
        {
            yield return new KeyValuePair<T, U>(default(T), secondEnumerator.Current);
        }
    }
    
    static void Test()
    {
        IList<string> names = new string[] { "one", "two", "three" };
        IList<int> ids = new int[] { 1, 2, 3, 4 };
    
        foreach (KeyValuePair<string, int> keyValuePair in ParallelEnumerate(names, ids))
        {
            Console.WriteLine(keyValuePair.Key ?? "<null>" + " - " + keyValuePair.Value.ToString());
        }
    }
    
        3
  •  11
  •   albertein    15 年前

    可以使用union或concat,前者删除重复项,后者不删除

    foreach (var item in List1.Union(List1))
    {
       //TODO: Real code goes here
    }
    
    foreach (var item in List1.Concat(List1))
    {
       //TODO: Real code goes here
    }
    
        4
  •  3
  •   Samuel Neff    15 年前

    这里有一个自定义的IEnumerable<gt;扩展方法,可用于同时循环两个列表。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace ConsoleApplication1
    {
        public static class LinqCombinedSort
        {
            public static void Test()
            {
                var a = new[] {'a', 'b', 'c', 'd', 'e', 'f'};
                var b = new[] {3, 2, 1, 6, 5, 4};
    
                var sorted = from ab in a.Combine(b)
                             orderby ab.Second
                             select ab.First;
    
                foreach(char c in sorted)
                {
                    Console.WriteLine(c);
                }
            }
    
            public static IEnumerable<Pair<TFirst, TSecond>> Combine<TFirst, TSecond>(this IEnumerable<TFirst> s1, IEnumerable<TSecond> s2)
            {
                using (var e1 = s1.GetEnumerator())
                using (var e2 = s2.GetEnumerator())
                {
                    while (e1.MoveNext() && e2.MoveNext())
                    {
                        yield return new Pair<TFirst, TSecond>(e1.Current, e2.Current);
                    }
                }
    
            }
    
    
        }
        public class Pair<TFirst, TSecond>
        {
            private readonly TFirst _first;
            private readonly TSecond _second;
            private int _hashCode;
    
            public Pair(TFirst first, TSecond second)
            {
                _first = first;
                _second = second;
            }
    
            public TFirst First
            {
                get
                {
                    return _first;
                }
            }
    
            public TSecond Second
            {
                get
                {
                    return _second;
                }
            }
    
            public override int GetHashCode()
            {
                if (_hashCode == 0)
                {
                    _hashCode = (ReferenceEquals(_first, null) ? 213 : _first.GetHashCode())*37 +
                                (ReferenceEquals(_second, null) ? 213 : _second.GetHashCode());
                }
                return _hashCode;
            }
    
            public override bool Equals(object obj)
            {
                var other = obj as Pair<TFirst, TSecond>;
                if (other == null)
                {
                    return false;
                }
                return Equals(_first, other._first) && Equals(_second, other._second);
            }
        }
    
    }
    
        5
  •  1
  •   thalm    8 年前

    如果列表的长度相同,也可以简单地使用局部整型变量:

    List<classA> listA = fillListA();
    List<classB> listB = fillListB();
    
    var i = 0;
    foreach(var itemA in listA)
    {
        Console.WriteLine(itemA  + listB[i++]);
    }
    
        6
  •  0
  •   Maximilian Mayerl    15 年前

    不,您必须使用for循环。

    for (int i = 0; i < lst1.Count; i++)
    {
        //lst1[i]...
        //lst2[i]...
    }
    

    你不能做这样的事

    foreach (var objCurrent1 int lst1, var objCurrent2 in lst2)
    {
        //...
    }
    
        7
  •  0
  •   albertein    15 年前

    如果你想要一个元素和对应的元素,你可以做

    Enumerable.Range(0, List1.Count).All(x => List1[x] == List2[x]);
    

    如果每个项都等于第二个列表中相应的项,则返回true。

    如果这几乎是你想要的,但不完全是你想要的,那么如果你更详细地阐述它会有所帮助。

        8
  •  0
  •   Rohan West    15 年前

    此方法适用于列表实现,可以作为扩展方法实现。

    public void TestMethod()
    {
        var first = new List<int> {1, 2, 3, 4, 5};
        var second = new List<string> {"One", "Two", "Three", "Four", "Five"};
    
        foreach(var value in this.Zip(first, second, (x, y) => new {Number = x, Text = y}))
        {
            Console.WriteLine("{0} - {1}",value.Number, value.Text);
        }
    }
    
    public IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(List<TFirst> first, List<TSecond> second, Func<TFirst, TSecond, TResult> selector)
    {
        if (first.Count != second.Count)
            throw new Exception();  
    
        for(var i = 0; i < first.Count; i++)
        {
            yield return selector.Invoke(first[i], second[i]);
        }
    }
    
        9
  •  0
  •   Matěj Pokorný    8 年前

    既然C 7,你可以使用元组…

    int[] nums = { 1, 2, 3, 4 };
    string[] words = { "one", "two", "three", "four" };
    
    foreach (var tuple in nums.Zip(words, (x, y) => (x, y)))
    {
        Console.WriteLine($"{tuple.Item1}: {tuple.Item2}");
    }
    
    // or...
    foreach (var tuple in nums.Zip(words, (x, y) => (Num: x, Word: y)))
    {
        Console.WriteLine($"{tuple.Num}: {tuple.Word}");
    }
    
        10
  •  -1
  •   Rigel1121    6 年前

    您还可以执行以下操作:

    var i = 0;
    foreach (var itemA in listA)
    {
      Console.WriteLine(itemA + listB[i++]);
    }
    

    注:长度 listA 必须与相同 listB .

        11
  •  -2
  •   Benjamin Podszun    15 年前

    我理解/希望列表的长度相同: 不,你唯一的赌注是用一个简单的旧标准循环。