可以将两个循环合并为一个循环吗?

时间:2016-08-23 13:27:34

标签: javascript arrays for-loop

我正在使用以下函数将特定数字添加到我后来想要分配给变量的数组中。为此,我使用了两个 flask run 循环,但我觉得有一种更简洁的方法可以做到这一点。我尝试将两个循环合并而不会出现错误,但输出结果不一样。

工作示例:

for

合并示例:

function fill () {
    var array = [];
    for (var index = 0; index < arguments.length; index++) {
        for (var number = arguments[index][0]; number <= arguments[index][1]; number++)
            array.push(number);
    }
    return array;
};

/* Use */
var keys = fill([1, 10], [32, 34]);

/* Output */
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 32, 33, 34]

是否可以将两个循环合并为一个?如果没有,有没有办法用更少的代码编写上述函数?

6 个答案:

答案 0 :(得分:1)

第一个例子中的代码很好。没有真正“干净”的方法来删除嵌套循环。

你可以用forEach迭代它们,但是你仍然有嵌套循环,即使其中一个伪装成函数调用:

function fill () {
    var array = [];
    Array.prototype.slice.apply(arguments) // Make an array out of arguments.
        .forEach(function(arg){
            for (var number = arg[0]; number <= arg[1]; number++){
                array.push(number);
            }
        });
    return array;
};

console.log(fill([1, 10], [32, 34]));

您必须使用Array.prototype.slice.applyarguments转换为实际数组。 (这很难看)

所以,基本上,嵌套循环不一定是“邪恶的”。你的第一个例子就像它一样好。

答案 1 :(得分:1)

JavaScript是一种功能语言。为了现代编码的目的,功能方法最适合编码人员的利益。

&#13;
&#13;
var fillArray = (...args) => args.reduce((res,arg) => res.concat(Array(...Array(arg[1]-arg[0]+1)).map((e,i) => i + arg[0])),[]),
       filled = fillArray([1, 10], [32, 34]);
console.log(filled);
&#13;
&#13;
&#13;

好的,这里发生的事情......很简单。我们通过fillArray函数完成工作。 fillArray函数需要无限数量的参数。因此,我们使用ES6 rest操作符args将它们全部收集在一个名为...的数组中。

var fillArray = (...args)

现在我们在args数组中有了源数组,我们将对此数组应用reduce操作,初始值为空数组(res)。我们要做的是..根据每个源(arg)数组,我们将创建一个新数组,然后我们将它连接到res数组。好吧,我们收到[1,10]作为来源,这意味着我们需要一个长度为arg [1] -arg [0] +1的数组。所以来了

Array(...Array(arg[1]-arg[0]+1))

我们也可以像Array(arg[1]-arg[0]+1).fill()那样做。我们现在有一个填充了"undefinite"所需长度的数组。然后是地图。这非常简单,因为我们应用于这个不确定的数组,如

.map((e,i) => i + arg[0]))

这意味着每个项目都是当前索引+偏移量,即arg[0] 然后我们将这个数组连接到我们的结果数组并传递给下一个源数组。所以你看它非常直接且可维护。

答案 2 :(得分:1)

你可能无法逃脱这两个循环,但这也不一定是目标。循环本身并不是真正有害的 - 只有当你多次迭代相同的数据而你可能想重新考虑你的代码时才会这样做

考虑这种完全不同的方法

&#13;
&#13;
const range = (x , y) =>
  x > y
    ? []
    : [ x, ...range (x + 1, y) ]

const concat = (xs, ys) =>
  xs .concat (ys);

const flatMap = (f, xs) =>
  xs .reduce ((acc, x) => concat (acc, f (x)), [])

const apply = f => xs =>
  f (...xs)

const fill = (...ranges) =>
  flatMap (apply (range), ranges);

console.log
  (fill ( [1,10]
        , [32,34]
        , [40,49]
        , [100,100]
        )
  )
&#13;
&#13;
&#13;

所以是的,@ Redu正在使用#34; JavaScript是一种功能性语言&#34;但我认为他/她的答案不能提供一个很好的功能性答案。

上面的答案显示了具有个性化问题的函数如何易于阅读,易于编写以及易于组合以实现复杂的计算。

答案 3 :(得分:0)

在ES6中,您可以使用rest运算符并根据项目构建一个新数组。

function fill(...p) {
    return p.reduce((r, a) => r.concat(Array.apply(null, { length: a[1] - a[0] + 1 }).map(() => a[0]++)), []);
};

var keys = fill([1, 10], [32, 34]);
console.log(keys);

答案 4 :(得分:0)

与另一个答案类似,但更完整一点:

const arrays = [[1,10],[32,34],[9,12]]
const range = (a,b) => a >= b ? [] :
    [...Array(b-a).keys()].map(i => i+a)
const result = arrays.reduce( (a,c) =>
     a.concat( range(c[0], c[1]+1) ), [] )

// =>   [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 32, 33, 34, 9, 10, 11, 12 ]

如果您更喜欢更传统的范围功能,那么:

const arrays = [[1,10],[32,34],[9,12]]

function range(a,b) {
    var arr = []
    for (let i = a; i < b; i++)
        arr.push(i)
    return arr
}

const result = arrays.reduce( function(a,c) {
    return a.concat( range(c[0], c[1]+1) )
}, [] )

答案 5 :(得分:-1)

在将近2年的时间里,在此线程上发布了一些不错的答案,提出了有趣的替代方案,我找到了一种将两个循环合并为一个的方法,但这并不妙!

代码:

object.getAllProperties()