【问题标题】:Get the last item in an array获取数组中的最后一项
【发布时间】:2011-03-14 01:27:54
【问题描述】:

到目前为止,这是我的 JavaScript 代码:

var linkElement = document.getElementById("BackButton");
var loc_array = document.location.href.split('/');
var newT = document.createTextNode(unescape(capWords(loc_array[loc_array.length-2]))); 
linkElement.appendChild(newT);

目前它从 URL 获取数组中倒数第二个项目。但是,我想检查数组中的最后一项是否为"index.html",如果是,则改为获取倒数第三项。

【问题讨论】:

    标签: javascript arrays es2022


    【解决方案1】:

    这个问题已经存在很长时间了,所以我很惊讶没有人提到在 pop() 之后将最后一个元素重新打开。

    arr.pop()arr[arr.length-1] 一样高效,并且两者的速度都与arr.push() 相同。

    因此,您可以逃脱:

    ---EDITED [在推送之前检查thePop 不是undefined]---

    let thePop = arr.pop()
    thePop && arr.push(thePop)
    

    ---结束编辑---

    这可以减少到这个(相同的速度[编辑:但不安全!]):

    arr.push(thePop = arr.pop())    //Unsafe if arr empty
    

    这比arr[arr.length-1] 慢两倍,但您不必用索引来解决问题。这在任何一天都值得黄金。

    在我尝试过的解决方案中,以 arr[arr.length-1] 的执行时间单位 (ETU) 的倍数计算:

    [方法].......[ETUs 5 elems]...[ETU 100 万元素]

    arr[arr.length - 1]      ------> 1              -----> 1
    
    let myPop = arr.pop()
    arr.push(myPop)          ------> 2              -----> 2
    
    arr.slice(-1).pop()      ------> 36             -----> 924  
    
    arr.slice(-1)[0]         ------> 36             -----> 924  
    
    [...arr].pop()           ------> 120            -----> ~21,000,000 :)
    

    最后三个选项,特别是[...arr].pop(),随着数组大小的增加变得非常糟糕。在没有我机器内存限制的机器上,[...arr].pop() 可能会保持 120:1 的比率。尽管如此,没有人喜欢资源狂。

    【讨论】:

    • 如果初始数组可以为空,这种方法会产生错误的结果,[] 会变成[undefined]。您需要使用明确的undefined 检查来保护向后推送,例如myPop !== undefined && arr.push(myPop)
    【解决方案2】:

    In ECMAScript proposalStage 1 建议添加一个数组属性,该属性将返回最后一个元素:proposal-array-last

    语法:

    arr.lastItem // get last item
    arr.lastItem = 'value' // set last item
    
    arr.lastIndex // get last index
    

    您可以使用polyfill

    提案作者:Keith Cirkel(chaiautor)

    【讨论】:

      【解决方案3】:

      如果您来这里寻找,这里还有更多 Javascript 艺术作品

      本着使用reduceRight()但更短的另一个答案的精神:

      [3, 2, 1, 5].reduceRight(a => a);
      

      它依赖于这样一个事实,即如果您不提供初始值,则选择最后一个元素作为初始值(查看文档here)。由于回调只是不断返回初始值,因此最后一个元素将是最后返回的元素。

      请注意,这应该被视为 Javascript 艺术,这绝不是我推荐的方式,主要是因为它在 O(n) 时间内运行,但也因为它损害了可读性。

      现在认真回答

      我看到的最佳方式(考虑到您希望它比array[array.length - 1] 更简洁)是这样的:

      const last = a => a[a.length - 1];
      

      那就用函数吧:

      last([3, 2, 1, 5])
      

      该函数在处理匿名数组(如上面使用的[3, 2, 1, 5])时非常有用,否则您必须实例化它两次,这将是低效且丑陋的:

      [3, 2, 1, 5][[3, 2, 1, 5].length - 1]
      

      呃。

      例如,在这种情况下,您有一个匿名数组并且您必须定义一个变量,但您可以改用 last()

      last("1.2.3".split("."));
      

      【讨论】:

        【解决方案4】:

        这个方法不会弄乱你的原型。它还防范0 长度数组以及null/undefined 数组。如果返回的默认值可能与数组中的某个项目匹配,您甚至可以覆盖默认值。

        const items = [1,2,3]
        const noItems = []
        
        /**
         * Returns the last item in an array.
         * If the array is null, undefined, or empty, the default value is returned.
         */
        function arrayLast (arrayOrNull, defVal = undefined) {
          if (!arrayOrNull || arrayOrNull.length === 0) {
            return defVal
          }
          return arrayOrNull[arrayOrNull.length - 1]
        }
        
        console.log(arrayLast(items))
        console.log(arrayLast(noItems))
        console.log(arrayLast(null))
        
        console.log(arrayLast(items, 'someDefault'))
        console.log(arrayLast(noItems, 'someDefault'))
        console.log(arrayLast(null, 'someDefault'))

        【讨论】:

          【解决方案5】:

          获取数组最后一项的简单方法:

          var last_item = loc_array.reverse()[0];
          

          当然,我们需要先检查确保数组至少有一项。

          【讨论】:

          • 这并没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方留下评论。 - From Review
          • 问题是“如何获取数组中的最后一项”,我的解决方案应该有效。 :)
          • 这是获取最后一个元素的最慢方法...如果数组有一百万个元素怎么办?
          • 可怕的可怕想法! reverse 改变了原始数组,所以如果你连续运行两次,你会得到不同的结果(假设长度> 1)
          【解决方案6】:

          这可以通过 lodash _.last_.nth 来完成:

          var data = [1, 2, 3, 4]
          var last = _.nth(data, -1)
          console.log(last)
          <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

          【讨论】:

            【解决方案7】:

            使用 Ramda 进行函数式编程

            如果您使用 JS,我建议您查看 Ramda,它是一个函数式编程库(类似于 Lodash 和 Underscore,除了更高级和模块化)。 Ramda 提供了 R.last

            import * as R from 'ramda';
            R.last(['fi', 'fo', 'fum']); //=> 'fum'
            R.last([]); //=> undefined
            
            R.last('abc'); //=> 'c'
            R.last(''); //=> ''
            

            它还提供initheadtailList monster from (Learn You a Haskell)

            【讨论】:

            • 包含库对于获取最后一个元素是不合理的,如果我这样做,我会使用underscorejs.org/#last
            • @Tebe Ramda 是更新的更现代和模块化的 Lodash 版本,它是 Underscore.js 的替代品
            • 是的,我尝试了 ramda,乍一看对我来说,它的味道有点过于复杂。也许我仍然认为功能不够,并且当我的思想准备好时会进入它。顺便说一句,我看到你有它的经验,在 ramda 中如何看待这样的代码? _.chain([1,2,3]).map((val)=> { return val*2 }).first().value() -> 结果为 2。它支持链接吗?我看到 ramda 有方法链,但它看起来像是为了其他东西
            • @Tebe Like this R.pipe(R.take(1), x=>x*2)(也适用于 typescript)
            • 我不明白为什么这个答案会受到如此多的反对! Ramda 可以说比 Lodash 和 Underscore 都好。它纯粹是功能性的和干净的,即使如果有人不习惯函数式编程可能有点难以理解。它绝对是解决问题的好方法,但如果您唯一要做的就是获取数组中的最后一个元素,我仍然不建议您使用库。
            【解决方案8】:

            如下所示:

            if ('index.html' === array[array.length - 1]) {  
               //do this 
            } else { 
               //do that 
            }
            

            如果使用 UnderscoreLodash,您可以使用 _.last(),例如:

            if ('index.html' === _.last(array)) {  
               //do this 
            } else { 
               //do that 
            }
            

            或者您可以创建自己的最后一个函数:

            const _last = arr => arr[arr.length - 1];
            

            并像这样使用它:

            if ('index.html' === _last(array)) {  
               //do this 
            } else { 
               //do that 
            }
            

            【讨论】:

              【解决方案9】:

              无论你做什么,都不要只是使用reverse() !!!

              一些答案​​提到了reverse,但没有提到reverse 修改了原始数组,并且不(如在某些其他语言或框架中)返回副本。

              var animals = ['dog', 'cat'];
              
              animals.reverse()[0]
              "cat"
              
              animals.reverse()[0]
              "dog"
              
              animals.reverse()[1]
              "dog"
              
              animals.reverse()[1]
              "cat"
              

              这可能是最难调试的代码类型!

              【讨论】:

              • 如果您确实想要数组的反向副本,您现在可以使用展开运算符。例如[...animals].reverse()
              • 你可以在使用反向之前简单地复制数组[1,3,4,5,"last"].slice().reverse()[0]
              【解决方案10】:

              为了防止从原始数组中删除最后一项,您可以使用

              Array.from(myArray).pop()
              

              大多数浏览器都支持 (ES6)

              【讨论】:

                【解决方案11】:

                const [lastItem] = array.slice(-1);

                Array.prototype.slice 和 -1 可用于创建仅包含原始 Array 的最后一项的新 Array,然后您可以使用 Destructuring Assignment 使用该新 Array 的第一项创建变量。

                const lotteryNumbers = [12, 16, 4, 33, 41, 22];
                const [lastNumber] = lotteryNumbers.slice(-1);
                
                console.log(lotteryNumbers.slice(-1));
                // => [22]
                console.log(lastNumber);
                // => 22

                【讨论】:

                • .slice(-1) 的答案已经多次给出,从in 2012 开始,其含义已详细讨论(与此处不同)。请不要为了获得点赞而重复回答。
                • 我最喜欢这个答案。我见过的其他 .slice(-1) 答案使用 [0] 而不是解构。 @diachedelic 的评论暗示了这种解构,但在我看来,它应该是一个答案而不是评论。很好的例子和链接。
                • 是的,其他答案不一样,丹,你错过了使用 slice(-1) 生成的数组中的解构赋值。
                【解决方案12】:
                array.reverse()[0]
                

                就是这么简单

                【讨论】:

                • 反向修改原始数组。您应该为此方法调用 Array.from(items).reverse()[0]。
                • 这会产生如此不必要的开销。即使有@TamusJRoyce 的建议,它仍然很糟糕,即使对于保证不超过两个项目的数组,我也不会使用它。
                【解决方案13】:

                在javascript中查找数组最后一个值的多种方法

                • 不影响原数组

                var arr = [1,2,3,4,5];
                
                console.log(arr.slice(-1)[0])
                console.log(arr[arr.length-1])
                const [last] = [...arr].reverse();
                console.log(last)
                
                let copyArr = [...arr];
                console.log(copyArr.reverse()[0]);
                • 修改原始数组

                var arr = [1,2,3,4,5];
                
                console.log(arr.pop())
                arr.push(5)
                console.log(...arr.splice(-1));
                • 通过创建自己的辅助方法

                let arr = [1, 2, 3, 4, 5];
                
                Object.defineProperty(arr, 'last', 
                { get: function(){
                  return this[this.length-1];
                 }
                })
                
                console.log(arr.last);

                【讨论】:

                • 如果您在第一个示例中声明 “不影响原始数组” 并按照建议进行操作:console.log(arr.reverse()[0]) - 恭喜,您刚刚修改了原始数组。
                【解决方案14】:

                要使用 c# 访问数组中的最后一个元素,我们可以使用 GetUpperBound(0)

                (0) 如果这个一维数组

                my_array[my_array.GetUpperBound(0)] //this is the last element in this one dim array
                

                【讨论】:

                • 问题是如何在 JavaScript 中做到这一点 :)
                【解决方案15】:

                只是在这里添加另一个选项。

                loc_array.splice(-1)[0] === 'index.html'
                

                我发现上述方法在网上更简洁。请随意尝试这个。

                注意:它会修改原始数组,如果不想修改可以使用slice()

                loc_array.slice(-1)[0] === 'index.html'
                

                感谢@VinayPai 指出这一点。

                【讨论】:

                • .slice(-1) 的答案已经多次给出,从 in 2012 开始,其含义已详细讨论(与此处不同)。请不要为了获得点赞而重复回答。
                • @DanDascalescu 谢谢你的客气话。这是一个诚实的错误,我之前在同一个问题上没有看到那个答案,并试图帮助我知道的。此外,如果upvotes 是我的最爱,那么您会在我的个人资料上看到更多重复的答案。
                • @DanDascalescu 任何方式,鼓励平台上的新成员的方式,以及展示他们错误的非常好的方式。向你致敬。来自如此强大的形象、倡导者、联合创始人非常鼓舞人心,我肯定会尽量不追随这样的影响者,并保持礼貌,让新成员感到舒适。谢谢你的课。这是一个很好的;)
                【解决方案16】:

                ES6 对象解构是另一种方法。

                const {length, [length-1]: last}=[1,2,3,4,5]
                console.log(last)

                您使用对象解构从 Array 中提取 length 属性。您使用 [length-1] 已提取的密钥创建另一个动态密钥,并将其分配给 last,全部在一行中。

                【讨论】:

                • 谢谢,你能解释一下它到底是做什么的吗?
                • 据我了解(我可能错了)length 是数组的第一个索引。但[length-1] 是最后一个索引(它之前的那个)。 :last 是用于定义最后一个索引的别名(或者确切地说是第一个索引之前的那个)
                • @TarunNagpal 数组就像对象,它们具有长度属性和索引作为属性。这里我们析构length 然后使用computed property name [length -1] 得到最后一个元素。
                【解决方案17】:

                我认为这应该可以正常工作。

                var arr = [1, 2, 3];
                var last_element = arr.reverse()[0];
                

                只需反转数组并获取第一个元素。

                编辑:如下所述,原始数组将被反转。为避免这种情况,您可以将代码更改为:

                var arr = [1, 2, 3];
                var last_element = arr.slice().reverse()[0];
                

                这将创建原始数组的副本。

                【讨论】:

                • 这将改变原始数组
                • slice() 复制数组 var arr = [1, 2, 3]; last_element = arr.slice().reverse()[0];
                • @Zellius 如果要对数组进行切片,也可能只弹出最后一个元素。即arr.slice().pop()
                【解决方案18】:

                要获得可读且简洁的解决方案,您可以使用Array.prototype.slicedestructuring 的组合。

                const linkElement = document.getElementById("BackButton");
                const loc_array = document.location.href.split('/');
                
                // assign the last three items of the array to separate variables
                const [thirdLast, secondLast, last] = loc_array.slice(-3);
                
                // use the second last item as the slug...
                let parentSlug = secondLast;
                
                if (last === 'index.html') {
                  // ...unless this is an index
                  parentSlug = thirdLast;
                }
                
                const newT = document.createTextNode(
                  unescape(
                    capWords(parentSlug)
                  )
                );
                
                linkElement.appendChild(newT);
                

                但要简单地获取数组中的最后一项,我更喜欢这种表示法:

                const [lastItem] = loc_array.slice(-1);
                

                【讨论】:

                  【解决方案19】:

                  性能

                  今天 2020.05.16 我在 MacOs High Sierra v10.13.6 上的 Chrome v81.0、Safari v13.1 和 Firefox v76.0 上执行所选解决方案的测试

                  结论

                  • arr[arr.length-1] (D) 被推荐为最快的跨浏览器解决方案
                  • 可变解决方案arr.pop() (A) 和不可变解决方案_.last(arr) (L) 速度很快
                  • 解决方案 I、J 对于长字符串来说很慢
                  • 解决方案 H、K (jQuery) 在所有浏览器上最慢

                  详情

                  我测试了两个案例的解决方案:

                  • 可变:A, B, C,

                  • 不可变:D, E, F, G, H, I, J(我的),

                  • 从外部库不可变:KL, M,

                  两种情况

                  • 短字符串 - 10 个字符 - 你可以运行测试 HERE
                  • 长字符串 - 1M 个字符 - 你可以运行测试 HERE

                  function A(arr) {
                    return arr.pop();
                  }
                  
                  function B(arr) {  
                    return arr.splice(-1,1);
                  }
                  
                  function C(arr) {  
                    return arr.reverse()[0]
                  }
                  
                  function D(arr) {
                    return arr[arr.length - 1];
                  }
                  
                  function E(arr) {
                    return arr.slice(-1)[0] ;
                  }
                  
                  function F(arr) {
                    let [last] = arr.slice(-1);
                    return last;
                  }
                  
                  function G(arr) {
                    return arr.slice(-1).pop();
                  }
                  
                  function H(arr) {
                    return [...arr].pop();
                  }
                  
                  function I(arr) {  
                    return arr.reduceRight(a => a);
                  }
                  
                  function J(arr) {  
                    return arr.find((e,i,a)=> a.length==i+1);
                  }
                  
                  function K(arr) {  
                    return $(arr).get(-1);
                  }
                  
                  function L(arr) {  
                    return _.last(arr);
                  }
                  
                  function M(arr) {  
                    return _.nth(arr, -1);
                  }
                  
                  
                  
                  
                  
                  
                  // ----------
                  // TEST
                  // ----------
                  
                  let loc_array=["domain","a","b","c","d","e","f","g","h","file"];
                  
                  log = (f)=> console.log(`${f.name}: ${f([...loc_array])}`);
                  
                  [A,B,C,D,E,F,G,H,I,J,K,L,M].forEach(f=> log(f));
                  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
                  <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js" integrity="sha256-VeNaFBVDhoX3H+gJ37DpT/nTuZTdjYro9yBruHjVmoQ=" crossorigin="anonymous"></script>

                  Chrome 的短字符串示例结果

                  【讨论】:

                    【解决方案20】:

                    您可以通过Array#at 使用相对索引:

                    const myArray = [1, 2, 3]
                    
                    console.log(myArray.at(-1))
                    // => 3
                    

                    【讨论】:

                    • 截至 2021 年 3 月,它仍在提案中,不受任何浏览器支持
                    • 现在在 chrome92 上支持它。 chromestatus.com/feature/6123640410079232
                    • 很好的答案,但如果有人指出这是一种新方法,并非所有现代浏览器都完全支持,旧浏览器也不支持,那就更好了。
                    • @M.Justin 有一个包含浏览器支持表的文档链接 — 应该足够了。我希望突出显示最现代的解决方案。大多数东西都可以自动填充或转译到旧环境中。在快速发展的生态系统中,开发人员可能应该重新考虑手动为旧环境编写代码,或者假设所有地方都支持一切。
                    【解决方案21】:

                    简单的回答

                    const array = [1,2,3]
                    array[array.length - 1]
                    

                    【讨论】:

                    • 很好的答案
                    【解决方案22】:

                    2020 年更新

                    Array.prototype.last = function(){
                        return this[this.length - 1];
                    }
                    
                    let a = [1, 2, 3, [4, 5]];
                    
                    console.log(a.last());
                    // [ 4, 5 ]
                    console.log(a.last().last());
                    // 5
                    

                    Setter 和 Getter

                    Array.prototype.last = function(val=null) {
                      if (this.length === 0) {
                        if (val) this[0] = val;
                        else return null; 
                      }
                      
                      temp = this;
                      while(typeof temp[temp.length-1] === "object") {
                        temp = temp[temp.length-1];
                      }
                      
                      if (val) temp[temp.length-1] = val; //Setter  
                      else return temp[temp.length-1]; //Getter
                      
                    }
                    
                    var arr = [[1, 2], [2, 3], [['a', 'b'], ['c', 'd']]];
                    console.log(arr.last()); // 'd'
                        
                    arr.last("dd"); 
                    console.log(arr); // [ [ 1, 2 ], [ 2, 3 ], [ [ 'a', 'b' ], [ 'c', 'dd' ] ] ]
                    

                    【讨论】:

                    • 请避免污染原型。
                    • @Sean,与重写原型相比,添加是一种更好的做法。
                    • 我不知道你想说什么,但是修改你不拥有的原型会使你的代码容易发生冲突并损害前向兼容性。原型污染是 JavaScript 安全公告发现的一种已知不良做法。
                    【解决方案23】:

                    通常你不应该弄乱内置类型的原型,但这里有一个技巧/捷径:

                    Object.defineProperty(Array.prototype, 'last', {
                      get() {
                        return this[this.length - 1]; 
                      }
                    });
                    

                    这将允许所有数组对象具有last 属性,您可以像这样使用它:

                    const letters = ['a', 'b', 'c', 'd', 'e'];
                    console.log(letters.last); // 'e'
                    

                    您不应该弄乱内置类型的原型,因为您永远不会在发布新的 ES 版本时,并且如果新版本使用与您的自定义属性相同的属性名称,各种中断都可以发生。此外,其他人很难遵循您的代码,特别是对于加入团队的人。您可以将属性设置为您知道 ES 版本永远不会使用的东西,例如 listLastItem,但这由开发人员自行决定。

                    或者你可以用一个简单的方法:

                    const getLast = (list) => list[list.length - 1];
                    const last = getLast([1,2,3]); // returns 3
                    

                    【讨论】:

                      【解决方案24】:
                      const [y] = x.slice(-1)
                      

                      快速解释

                      这种语法[y] = &lt;array/object&gt; 被称为解构赋值,根据 Mozilla 文档,解构赋值可以将数组中的值或对象的属性解压缩到不同的变量中

                      了解更多信息:here

                      【讨论】:

                      • 只使用arr[arr.length - 1] 肯定更好,因为它在大多数浏览器上更具可读性和快一个数量级。
                      • @acnebs 我同意,既然可以让它变得更容易,为什么还要让它变得更难。
                      【解决方案25】:
                      var str = ["stackoverflow", "starlink"];
                      var last = str[str.length-1];//basically you are putting the last index value into the array and storing it in la
                      

                      【讨论】:

                        【解决方案26】:

                        可以通过length 属性获取最后一项。由于数组计数从 0 开始,您可以通过引用 array.length - 1 项来选择最后一项。

                        const arr = [1,2,3,4];
                        const last = arr[arr.length - 1];
                        console.log(last); // 4

                        另一个选项是使用at 方法,它接受一个整数值并返回该索引处的项目。负整数从数组中的最后一项开始倒数,所以如果我们想要最后一项,我们可以传入-1

                        const arr = [1,2,3,4];
                        const last = arr.at(-1);
                        console.log(last); // 4

                        【讨论】:

                          【解决方案27】:

                          2021 年 10 月 27 日更新

                          Proposal for Array.prototype.findLast 现在处于第 3 阶段!

                          你可以这样使用它:

                          const array = [1, 2, 3, 4, 5];
                          
                          const last_element = array.findLast((item) => true);
                          console.log(last_element)

                          【讨论】:

                            【解决方案28】:

                            根据 ES2022,您可以使用 Array.at() 方法,该方法采用整数值并返回该索引处的项目。允许正整数和负整数。负整数从数组的最后一项开始倒数。

                            演示:

                            const href = 'www.abc.com/main/index.html';
                            const loc_array = href.split('/');
                            
                            // To access elements from an array we can use Array.at()
                            console.log(loc_array.at(-1)); // This will return item at last index.

                            【讨论】:

                              猜你喜欢
                              • 1970-01-01
                              • 1970-01-01
                              • 2017-09-29
                              • 1970-01-01
                              • 2020-05-13
                              • 1970-01-01
                              • 1970-01-01
                              • 2014-09-26
                              相关资源
                              最近更新 更多