【问题标题】:JavaScript initializing/appending/updating array of arraysJavaScript 初始化/追加/更新数组数组
【发布时间】:2016-09-25 18:53:59
【问题描述】:

我是 javascript 的新手,并且已经研究了很长时间,但无法弄清楚这种语法。当我尝试将一个数组推入另一个数组时,它会单独推入元素,而不是像我想要的那样创建一个数组数组。

我正在尝试做的事情:

lastTimes 作为数组数组:

lastTimes = [[1, 12435235], [2,443531923], [3,4925951]]

如果:IDandTime = [5, 5959393]

IDandTime 附加到lastTimes 作为数组:

lastTimes = [[1, 12435235], [2,443531923], [3,4925951], [5, 5959393]]

或者如果 ID (IDandTime[0]) 已经存在,则更新该数组在 lastTimes 内的时间:

如果IDandTime = [1, 50305240] 将 ID 1 的时间更新为 50305240:

lastTimes = [[1, 50305240], [2,443531923], [3,4925951], [5, 5959393]]

有人介意帮助我吗?我尝试了许多语法组合,但都无法正确使用,也未能成功找出正确的搜索词来找到预先存在的答案。非常感谢任何建议。

编辑:

代码:

var lastTimes = [];
var IDandTime = [1, 5935935];
lastTimes.push(IDandTime);

结果:

lastTimes = [1, 5935935]

我想要的结果:

lastTimes = [[1, 5935935]]

EDIT2:

好的,这是我正在使用的全部功能。我有一个带有 XBee 串行模块的 node.js 服务器,以及几个带有 XBee 串行模块的 Arduino 温度传感器。我有一个握手机制,但我试图在节点退出时实现错误检查,因此不再使用它们的陈旧数据。我觉得这实际上只是基本二维数组语法的问题。

// Open a new serial port connection 
sp.on("open", function (err) {
    if (err) {
        return console.log('Error opening port: ', err.message);
    }
    console.log('open');


    var nodeCount = 0;
    var nodes = []; // get rid of after debugging
    var lastTimes = [];
    lastTimes[0] = [0,0]; // initalize as 2D array for later


    //  Grab data from buffer
    sp.on('data', function(data) {
        // Initialize time Object
        var time = new Date();
        // Split incoming data by newline
        var buffer0 = data.split('\n');

        // New node handshake initiation received
        if (buffer0 == "BROADCASTING") {
            nodeCount++;
            var sendID = nodeCount.toString();
            sp.write(sendID);
            console.log("Broadcast received. Sending identifier #" + sendID);
            nodes.push(nodeCount);
        }

        // Preconnected node data received
        if ((buffer0 != "BROADCASTING") && (nodeCount > 0)) {
            var receiveTime = time.getTime();
            // [ID, Temp] touple
            var nodeData = buffer0[0].split(" ");
            console.log("NodeID: " + nodeData[0] + "    Temp(F): " + nodeData[1]);          
            // [ID, Time] touple
            var IDandTime = [];
            IDandTime.push(nodeData[0]);
            IDandTime.push(time.getTime());
            console.log("IDandTime: " + IDandTime);

            // Check for preexisting node ID
            var oldNode = 0; 
            var nodeIndex = 0;
            for (var i = 0; i < lastTimes.length; i++) {
                if (lastTimes[i][0] == IDandTime[0]) {
                    oldNode = 1;
                    nodeIndex = i;
                }
            }
            // If new node, add new node data to lastTimes (list of [ID, Time] touples)
            if (oldNode == 0) {
                lastTimes[lastTimes.length] = IDandTime;
                console.log("lastTimes: " + lastTimes);
            }
            // If preexisting node, update preexisting node time
            else if (oldNode == 1) {
                lastTimes[i][1] = IDandTime[1];
            }




        }



    });
});

我上次尝试找到正确语法的错误:

                lastTimes[i][1] = IDandTime[1];
                                ^

TypeError: Cannot set property '1' of undefined

【问题讨论】:

  • 如果您向我们提供用于将数组放入数组中的代码,那么我们或许可以告诉您为什么它没有按照您的意愿行事。
  • 这里可以使用 ES6 MAP。即使只是作为如何做的参考。
  • 我没有发布代码,因为它混合了太多不相关的部分(使用 node.js 作为无线模块的服务器),我认为它会混淆实际问题,我认为我在帖子里说清楚了。在大多数情况下,我尝试了IDandTime = [1, 59395] 然后lastTimes.push(IDandTime) 的许多组合,而不是导致lastTimes = [[1,59395]],导致lastTimes = [1, 59395]
  • it has so much irrelevant parts mixed in 我们不需要不相关的部分,只需要相关的部分 - 你如何尝试将一个数组推入另一个数组。
  • 使用 ES5 或 ES6 更干净,@NenadVracar 发布的答案就是一个很好的例子。但是,如果您阅读了有关Map 的信息,那么您会发现您同样可以使用 Javascript 对象文字,就像 @ZoltanTamasi 建议的那样。由于您使用的是最新版本的 Node,如果我是您,我会开始使用 ES6。还请查看 codereview.stackexchange.com 以获取有效的代码,但您正在寻求改进。

标签: javascript list multidimensional-array push


【解决方案1】:

您可以使用findIndex 检查第一个数字是否在数组中的某些元素中,并更改原始数组中的元素或将新元素推送到数组中。

var lastTimes = [[1, 12435235], [2,443531923], [3,4925951]];

function update(val) {
  var i = lastTimes.findIndex(function(e) {
    return e[0] == val[0];
  });

  if (i != -1) {
    lastTimes[i][1] = val[1];
  } else {
    lastTimes.push(val);
  }
}


update([1, 50305240])
console.log(lastTimes)

【讨论】:

  • 注意:Array#findIndex 是一种 ES6 方法,但完全可以调整。否则这是 ES3。我也有一个例子,但我希望 OP 首先展示他们的问题。 :)
【解决方案2】:

首先,如果data 是字符串,则调用data.split('\n') 会返回数组(请参阅String.prototype.split()),因此您的每个比较if (buffer0 == "BROADCASTING") 都会被评估为false。你可能想比较数据的第一行,第一行在buffer0[0],所以写条件if (buffer0[0] == ... )

那你的代码有错误

// If preexisting node, update preexisting node time
else if (oldNode == 1) {
    lastTimes[i][1] = IDandTime[1];
}

你在哪里使用来自循环的变量i,但是因为循环不是用break关键字终止的,所以循环总是遍历整个数组,循环结束后,变量i被设置为lastTimes.length,指向数组中不存在的索引。

我会这样写循环:

var IDandTime = [];
var nodeIndex = nodeData[0];
IDandTime.push(nodeIndex);
IDandTime.push(time.getTime());

var foundAtIndex;
for (var i = 0, l = lastTimes.length; i < l; i++) {
    if (lastTimes[i][0] === nodeIndex) {
        foundAtIndex = i;
        break;
    }
}

if (typeof foundAtIndex === 'undefined') {
     lastTimes.push(IDandTime);
} else {
    lastTimes[foundAtIndex] = IDandTime;
}

【讨论】:

  • 它是否默认为[0] 索引?因为无论如何它似乎都在工作,即使我意识到这看起来确实是个问题。对于第二期,也谢谢。我的意思是使用nodeIndex = i,然后使用lastTimes[nodeIndex][1],这样我就不需要break,但我想两者都可以。
  • 这是您遇到的另一个问题。如果您还查看npmjs.com/package/serialport,您将看到为您执行此拆分的选项parser: SerialPort.parsers.readline('\n')。但是您的代码仍然存在上述问题。 break 是停止循环所必需的,因为一旦找到所需的内容,您就无需继续寻找。即使你使用另一个变量来存储i
  • @Jake,JS 中的数组不默认为第一个元素,String.prototype.split() 总是返回一个 Array 且 Array 不等于 String(虽然 string 和 array 有很多共同点),所以如果data 参数确实是一个字符串(显然是),那么 buffer0 == "BROADCASTING" 可能永远不会计算为真。
【解决方案3】:

您可以使用纯对象(没有原型)而不是数组,如下所示:

var lastTimes = Object.create(null);

你可以设置这个对象的属性,而不是推送一个元组。这样您就不必手动处理更新或追加,一切都会自动运行,如下所示:

var receiveTime = time.getTime();
// [ID, Temp] touple
var nodeData = buffer0[0].split(" ");
console.log("NodeID: " + nodeData[0] + "    Temp(F): " + nodeData[1]);          
// [ID, Time] touple
var IDandTime = [];
IDandTime.push(nodeData[0]);
IDandTime.push(time.getTime());
console.log("IDandTime: " + IDandTime);

lastTimes[nodeData[0]] = time.getTime();

迭代值:

Object.keys(lastTimes).forEach(id => {
    var value = lastTimes[id];
});

通过 id 查找值只是:

var value = lastTimes[id];

【讨论】:

  • Object.create(null); 可以简化为 {}Object.create() 只有在你想用一些原型创建对象时才有意义。如果你想要带有prototype = null 的对象,那么{} 就是那个对象。
  • 这不是真的。 {} 将使用 Object 作为构造函数创建一个对象,生成的对象将“继承”诸如“hasOwnProperty”之类的函数。试试看:console.log({}.hasOwnProperty) console.log(Object.create(null).hasOwnProperty)
  • 你是对的。这两种方法都会产生新的object,而没有prototype,但Object.create(null) 的输出也有constructor === undefined,这很有趣,我不知道。但它的后果很少,(即使for ... in 循环的工作方式相同——你不必使用hasOwnProperty()),所以我认为没有动机使用更冗长和不太熟悉的Object.create(null),或者我错了?
  • {} 将创建一个实际上具有原型的对象:Object.prototype。检查这个:console.log(({}).__proto__ === Object.prototype)。是的,这是真的,它的后果很少。每当您在对象上查找属性时,JS 都会开始遍历原型链。遍历 1 个原型和 0 个原型是一个非常细微的区别,我猜差别很小,甚至不会出现在性能测试中。
  • 无论如何我喜欢区分 {} 和 Object.create(null),因为从代码中可以清楚地看到意图的差异。当我想要一个对象时我更喜欢使用 {},当我想要的不是真正的对象但我只想使用对象的类似 hashmap 的行为时使用 Object.create(null),就像在上面的场景中一样。
猜你喜欢
  • 2015-10-03
  • 2018-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多