【问题标题】:Best way to replace missing/undefined values in an array?替换数组中缺失/未定义值的最佳方法?
【发布时间】:2014-04-20 03:17:08
【问题描述】:

我需要处理一些包含undefined 值的数组,如下所示:

[ 1, 1, 1, 1, 1, , 1, 1 ]
[ 1, , 1, , , 1, 1 ]
[ 1, , , , , 1, 1 ]

我需要实现的是不是删除 undefined 值,但我需要用零替换它们。

我尝试使用underscore.js 来实现这一点;没有成功。

以下是我的解决方案尝试:

binarymap = _.map(binarymap, function(curr){
    // let's replace all undefined with 0s
    if(_.isUndefined(curr)) {
        return 0;
    }
    return curr;
});

不幸的是,它不起作用。 underscore.js 的函数 _.map 完全忽略了 undefined 的值。

有什么想法吗?优雅的解决方案?

【问题讨论】:

  • 我认为你不能使用 map 函数,我在 chrome 中尝试过 [ 1, , , , , 1, 1 ].map(function(){console.log(arguments);}); 并且我只有 3x 输出而不是 8 左右
  • @EricG 正是,这就是为什么我想知道是否有一个好的选择
  • 我怀疑下划线使用了所有可用的最新数组方法,我很确定mapfilter 等都忽略了undefined 值。
  • 如果您查看标准部分 15.4.4.198.12.6Array#map 实际上应该以这种方式工作,忽略数组中存在的未定义值。
  • 太脏了,但我不得不分享:var arr = [ 1, 1, 1, 1, 1, , 1, 1 ]; arr = JSON.parse(JSON.stringify(arr).replace(/null/g,0));

标签: javascript arrays list map underscore.js


【解决方案1】:

这里的实际问题是missing array elements

数组元素可以在开头、中间或结尾省略 元素列表。每当元素列表中的逗号前面没有 一个AssignmentExpression(即开头或之后的逗号 另一个逗号),缺少的数组元素会影响 Array 并增加后续元素的索引。消去数组 元素未定义。如果一个元素在一个结尾被省略 数组,该元素不会影响数组的长度。

Array.prototype.map 会跳过所有缺失的数组元素,

callbackfn 仅对数组的元素调用,实际上 存在;数组的缺失元素不会调用它。

所以,为了使 map 函数考虑数组元素,我能想到的最简单的方法是稍微调整一下你的方法,像这样

var arr = [ 1, , , , , 1, 1 ];
console.log(_.map(Array.apply(null, arr), function (currentItem) {
    return _.isUndefined(currentItem) ? 0 : currentItem;
}));
# [ 1, 0, 0, 0, 0, 1, 1 ]

在这里,Array.apply(实际上是Function.prototype.apply)做了重要的事情,将缺失的元素转换为undefined

console.log(Array.apply(null, arr));
# [ 1, undefined, undefined, undefined, undefined, 1, 1 ]

【讨论】:

    【解决方案2】:

    这是你的意思吗..?

    var arr = [ 1, , , , , 1, 1 ];
    for( var i = 0; i < arr.length; i++ ) {
     if( typeof(arr[i])==="undefined" ) {
      arr[i] = 9;
     }
    }
    console.log( arr );
    
    // yields [1, 9, 9, 9, 9, 1, 1] 
    

    【讨论】:

    • 是的,这就是我的意思。但我想知道是否可以通过使用 underscore.js 的函数或类似函数来实现优雅的解决方案。
    • 我觉得这个if( arr[i] === undefined ) {... 看起来更好。
    • @c-smile 这是一些安全的东西,可以防止有人写var undefined = 12时出错。
    • @francescostablum 我不能给你一个更优雅的解决方案我对下划线 js 不太熟悉。我只能给你一个解决方案。
    • @EricG 在这种偏执的情况下,您可以使用var nothing = {}.nothing; 并将其与该值进行比较。它会比字符串比较更有效。
    【解决方案3】:

    自发布后可能发生了一些变化,但underscore (v1.8.3) 和 lodash (v4.13.1) 都处理得很好:

    var u = [1, , , , , 1, 1];
    _.map(u, function(n) { return n || 0; });
    
    // [1, 0, 0, 0, 0, 1, 1]
    

    本机循环跳过未定义的条目,因为它们仅显式循环遍历数组的已定义元素 (ref)。源数组不包含 undefined 元素,它包含根本未定义的元素。

    这些数组是不同的:

    [1, undefined, 1]
    [1, , 1]
    

    第一个数组将其第一个索引定义为undefined
    第二个数组根本没有定义第一个索引。
    两者的长度都是 3。

    这感觉就像它开始进入WAT 边缘,但这是一个值得了解的细微差别。

    由于我们已经陷入困境,因此有一个复杂的原生解决方案我永远不会在现实生活中使用:

    var u = [1, , , , , 1, 1];
    Array(u.length).join(0).split('').map(function(n, i) { return u[i] || 0; })
    
    // [1, 0, 0, 0, 0, 1, 1]
    

    Array(u.length).join(0).split('') 产生一个任意字符串的虚拟数组,然后可以对其进行映射。 map 函数通过索引引用原始数组,然后使用简单的布尔开关返回定义的值或零。

    【讨论】:

      【解决方案4】:

      如果您愿意,您可以将该函数添加为 mixin 以在下划线链中使用。即兴创作自here

      _.mixin({
        dothis: function(obj, interceptor, context) {
          return interceptor.call(context, obj);
        }
      });
      
      function resetArray(arr) {
        for (var i = 0, l = arr.length; i < l; i++) {
          if (arr[i] === undefined) arr[i] = 0;
        }
        return arr;
      }
      
      var arr = [ 1, , , , , 1, 1 ];
      
      _(arr)
        .chain()
        .dothis(resetArray)
        .tap(console.log) // [1, 0, 0, 0, 0, 1, 1]
      

      Fiddle

      编辑:实际上,有一种更简单的方法:

      _.mixin({
        resetArray: function (arr) {
          for (var i = 0, l = arr.length; i < l; i++) {
              if (arr[i] === undefined) arr[i] = 0;
          }
          return arr;
        }
      });
      
      var arr = [1, , , , , 1, 1];
      
      _(arr)
        .chain()
        .resetArray()
        .tap(console.log)
      

      Fiddle

      【讨论】:

      • @francesco,我刚刚为更简单的解决方案添加了更新。
      【解决方案5】:

      如果您只需要从数组中删除空元素,则无需使用下划线,只需使用 splice 遍历数组删除空元素即可。

      您可以在 javascript 中添加该功能原型 Array 类:

      var array = [ 1, 1, , , , , 1, 1 ]; 
      
          Array.prototype.replaceEmptyElements = function(value) {
            for (var i = 0; i < this.length; i++) {
              if (typeof this[i] == "undefined") {         
                this[i] = value;
              }
            }
            return this;
          };
      
      var val = //your value
      array.replaceEmptyElements(val);
      

      【讨论】:

      • 我相信这个array = array.filter(function() { return true; }) 会更有效地实现这个目的。
      • @c-smile 他不想过滤,他想要undefined 值的另一个值(即长度应该保持不变)
      猜你喜欢
      • 2021-07-17
      • 2015-03-27
      • 1970-01-01
      • 1970-01-01
      • 2020-11-14
      • 1970-01-01
      • 1970-01-01
      • 2023-01-24
      • 1970-01-01
      相关资源
      最近更新 更多