当前位置:  开发笔记 > 编程语言 > 正文

如何一次迭代两个数组?

如何解决《如何一次迭代两个数组?》经验,为你挑选了2个好方法。

我在解析文本文件时构建了两个数组.第一个包含列名,第二个包含当前行的值.我需要一次迭代两个列表来构建一个地图.现在我有以下内容:

var currentValues = currentRow.Split(separatorChar);
var valueEnumerator = currentValues.GetEnumerator();

foreach (String column in columnList)
{
    valueEnumerator.MoveNext();
    valueMap.Add(column, (String)valueEnumerator.Current);
}

这很好用,但它并不能完全满足我的优雅感,如果阵列的数量大于2,它会变得非常毛茸茸(我偶尔也会这样做).有没有人有另一个更高级的成语?



1> Jon Skeet..:

你的初始代码中有一个非明显的伪bug - IEnumerator扩展IDisposable所以你应该处理它.这对于迭代器块来说非常重要!对于数组来说不是问题,但是与其他IEnumerable实现一样.

我这样做:

public static IEnumerable PairUp
    (this IEnumerable source, IEnumerable secondSequence,
     Func projection)
{
    using (IEnumerator secondIter = secondSequence.GetEnumerator())
    {
        foreach (TFirst first in source)
        {
            if (!secondIter.MoveNext())
            {
                throw new ArgumentException
                    ("First sequence longer than second");
            }
            yield return projection(first, secondIter.Current);
        }
        if (secondIter.MoveNext())
        {
            throw new ArgumentException
                ("Second sequence longer than first");
        }
    }        
}

然后,只要有需要,您就可以重复使用:

foreach (var pair in columnList.PairUp(currentRow.Split(separatorChar),
             (column, value) => new { column, value })
{
    // Do something
}

或者,您可以创建一个通用的Pair类型,并在PairUp方法中删除projection参数.

编辑:

使用Pair类型,调用代码如下所示:

foreach (var pair in columnList.PairUp(currentRow.Split(separatorChar))
{
    // column = pair.First, value = pair.Second
}

这看起来就像你能得到的一样简单.是的,您需要将实用程序方法放在某处,作为可重用的代码.在我看来,这几乎不成问题.现在有多个阵列......

如果数组的类型不同,我们就会遇到问题.您不能在泛型方法/类型声明中表达任意数量的类型参数 - 您可以根据需要为尽可能多的类型参数编写PairUp的版本,就像最多4个委托参数的委托ActionFunc委托一样- 但是您可以不要随意.

但是,如果这些值都属于同一类型 - 并且如果你很乐意坚持使用数组 - 这很容易.(非阵列也没关系,但你不能提前做长度检查.)你可以这样做:

public static IEnumerable Zip(params T[][] sources)
{
    // (Insert error checking code here for null or empty sources parameter)

    int length = sources[0].Length;
    if (!sources.All(array => array.Length == length))
    {
        throw new ArgumentException("Arrays must all be of the same length");
    }

    for (int i=0; i < length; i++)
    {
        // Could do this bit with LINQ if you wanted
        T[] result = new T[sources.Length];
        for (int j=0; j < result.Length; j++)
        {
             result[j] = sources[j][i];
        }
        yield return result;
    }
}

那么调用代码将是:

foreach (var array in Zip(columns, row, whatevers))
{
    // column = array[0]
    // value = array[1]
    // whatever = array[2]
}

这涉及到一定程度的复制,当然 - 每次都要创建一个数组.您可以通过引入另一种类型来改变它:

public struct Snapshot
{
    readonly T[][] sources;
    readonly int index;

    public Snapshot(T[][] sources, int index)
    {
        this.sources = sources;
        this.index = index;
    }

    public T this[int element]
    {
        return sources[element][index];
    }
}

尽管如此,这可能被视为过度杀伤;)

我可以不断提出各种想法,说实话......但基本要素是:

通过一些可重用的工作,您可以使调用代码更好

对于任意类型的组合,由于泛型的工作方式,您必须分别执行每个参数(2,3,4 ...)

如果您乐意为每个部件使用相同的类型,您可以做得更好


当单个for循环可能起作用时,它看起来过于复杂.

2> inkedmn..:

如果列名与每行中的元素数相同,那么你不能使用for循环吗?

var currentValues = currentRow.Split(separatorChar);

for(var i=0;i


我建议在进入此循环之前检查两个数组的长度是否相同.
推荐阅读
大大炮
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有