选择JavaScript数组中的最后一个元素[重复]
Posted
技术标签:
【中文标题】选择JavaScript数组中的最后一个元素[重复]【英文标题】:Selecting last element in JavaScript array [duplicate] 【发布时间】:2012-02-21 10:46:07 【问题描述】:我正在制作一个实时更新用户位置和路径并将其显示在 Google 地图上的应用程序。我的功能允许使用每秒更新的对象同时跟踪多个用户。
现在,当用户在 android 应用中按下按钮时,坐标会发送到数据库,并且每次位置发生变化时,都会在地图上更新一个标记(并形成一条折线)。
由于我有多个用户,我发送一个唯一且随机生成的字母数字字符串,以便我可以为每个用户显示单独的路径。当 JS 从数据库中提取这些数据时,它会检查用户是否存在,如果不存在,它会创建一个新键,其值为列表。它看起来像这样:
loc = f096012e-2497-485d-8adb-7ec0b9352c52: [new google.maps.LatLng(39, -86),
new google.maps.LatLng(38, -87),
new google.maps.LatLng(37, -88)],
44ed0662-1a9e-4c0e-9920-106258dcc3e7: [new google.maps.LatLng(40, -83),
new google.maps.LatLng(41, -82),
new google.maps.LatLng(42, -81)]
我正在做的是将坐标列表存储为键的值,即用户的 ID。每次通过添加到列表中更改位置时,我的程序都会不断更新此列表(这可以正常工作)。
我需要做的是每次位置更改时更新标记的位置。我想通过选择数组中的最后一项来做到这一点,因为那将是最后一个已知位置。现在,每次更改位置时,都会向地图添加一个新标记(示例中的每个点都会在该位置显示一个标记),因此会继续添加标记。
每次位置更新时,我都会使用“for (x in loc)”语句从列表中获取最后一个位置并使用它来更新标记。如何从哈希中的数组中选择最后一个元素?
【问题讨论】:
@tomdemuyt:loc
不是 OP 询问的数组。 loc['f096012e-2497-485d-8adb-7ec0b9352c52']
(或loc['f096012e-2497-485d-8adb-7ec0b9352c52']
)是。
以相反的顺序存储您的位置并调用 loc[0] 怎么样?
@Christophe 我也想过这个问题,但如果他跟踪它们一段时间,他将轻松获得超过 1,000 个位置,性能可能会成为问题。追加到末尾比将它们向下移动要快得多。
@LeviMorrison:如果可以选择更改数组,那么您可以简单地使用unshift()
,这应该比手动“移动”元素快得多。要在数组中只有 1000 个元素,并将它们添加到开头,只需使用以下命令(其中arr
是存储要存储的元素的数组):arr.unshift(new_element); arr.splice(1000);
。 unshift()
在数组的开头添加元素,splice(1000)
删除前 1000 个元素之后的所有内容(如果数组更短,则不会删除任何内容)。它符合您的需求吗?
使用.length-1
将是the fastest 它看起来像。
【参考方案1】:
如何访问数组的最后一个元素
看起来是这样的:
var my_array = /* some array here */;
var last_element = my_array[my_array.length - 1];
在你的情况下看起来像这样:
var array1 = loc['f096012e-2497-485d-8adb-7ec0b9352c52'];
var last_element = array1[array1.length - 1];
或者,在更长的版本中,不创建新变量:
loc['f096012e-2497-485d-8adb-7ec0b9352c52'][loc['f096012e-2497-485d-8adb-7ec0b9352c52'].length - 1];
如何添加更简单的方法
如果您喜欢创建函数/快捷方式来完成此类任务,请使用以下代码:
if (!Array.prototype.last)
Array.prototype.last = function()
return this[this.length - 1];
;
;
将允许您通过调用数组的 last()
方法来获取数组的最后一个元素,例如:
loc['f096012e-2497-485d-8adb-7ec0b9352c52'].last();
你可以在这里检查它是否有效:http://jsfiddle.net/D4NRN/
【讨论】:
老实说,如果这是他的应用程序的关键部分,他应该使用对象,而不仅仅是原型原语。见my post。 @LeviMorrison:您的回答更多是关于组织脚本/项目,而不是解决这个特定问题。向原型添加(自定义)函数可能不是那么干净,但老实说:arr[arr.length - 1]
是访问arr
数组的最后一个元素的常见且易于理解的方式。
这是一个旧答案,但尤其是现在请避免改变任何内置原型(例如,Array.prototype.last =
是一个不安全的分配)。
我不是第一个这么说的人,也不会是最后一个:不要修改你不拥有的对象——尤其是原生原型。当 javascript 在 ES 规范中实现相同的方法名称但与您的略有不同时会发生什么?坏事。 Prototype 和 Sugar.js 都修改了 native。最后,他们花费的时间和金钱都比他们节省的要多。
我一直想知道为什么 JavaScript 不能将它从 this.locations[this.locations.length-1]
减少到 this.locations[-1]
。这不是让我们的生活更轻松吗?有什么理由不这样做?【参考方案2】:
使用slice()
方法:
my_array.slice(-1)[0]
【讨论】:
这是一个很好的答案!它可以在单行中使用(my_array
可以替换为返回数组的表达式或函数),并且您不必对 Array
原型进行全局更改。
也是extremely slow。
确实这个很慢,可以参考jsperf.com/last-element-of-array-xxx
它相对慢,但不是绝对慢。比替代方案慢约 100 倍,但较慢的版本仍然在我的浏览器中每秒执行近 1000 万次。
我添加了一个test case,您可以在其中连续调用.pop()
和.push()
。似乎比 .slice(-1)[0]
快 10 倍,但仍然比直接访问慢 10 倍。【参考方案3】:
您也可以.pop
关闭最后一个元素。 小心,这会改变数组的值,但这对你来说可能没问题。
var a = [1,2,3];
a.pop(); // 3
a // [1,2]
【讨论】:
慢慢看测试jsperf.com/last-element-of-array-xxx/2 @JosefJezek:是的,慢一点。但是,我的意思是,你仍然可以在一秒钟内完成 2 亿次这样的操作,所以在这种情况下,最好担心什么是最可读的,而不是担心性能。 (当然,除非您尝试每秒执行数亿次) 只要使用arr.concat().pop()
【参考方案4】:
使用 es6 解构数组和扩展运算符
var last = [...yourArray].pop();
注意 yourArray 不会改变。
【讨论】:
这不会创建yourArray
的副本,弹出最后一个元素然后扔掉临时副本吗?如果yourArray
有大量元素,我认为这将是一项代价高昂的操作。
@chitti 或者他们只是转到最后一个索引并为您提供该元素的副本【参考方案5】:
var arr = [1, 2, 3];
arr.slice(-1).pop(); // return 3 and arr = [1, 2, 3]
如果数组为空,这将返回 undefined 并且不会改变数组的值。
【讨论】:
我喜欢这个。它不会像arr[arr.length - 1];
那样快,因为您正在实例化一个新数组,但至少它不是一些缓慢和/或破坏性的方法arr.reverse()[0]
或[...arr].pop();
,而且您不会改变内置的-在原型中(非常糟糕的做法),就像大多数其他解决方案一样。我要补充一点,现在你可以使用解构赋值并取消pop()
,这在某些情况下可能是有意义的。例如const arr = [1,2,3]; const [last] = arr.slice(-1);
很好,结果很完美。【参考方案6】:
var last = array.slice(-1)[0];
我发现 -1 处的 slice 对于获取最后一个元素(尤其是未知长度的数组)很有用,而且性能比计算长度小于 1 的要好得多。
Mozilla Docs on Slice
Performance of the various methods for selecting last array element
【讨论】:
+1 为jsperf.com/get-last-item-from-array JavaScript 性能链接,但是,对于我尝试过的浏览器和计算机array[array.length - 1]
至少执行array.slice(-1)[0]
40:1。
刚刚点击了我自己的链接并意识到我误读了图表:-P【参考方案7】:
Underscore 和 Lodash 具有 _.last(Array)
方法,它返回数组中的最后一个元素。它们的工作原理相同
_.last([5, 4, 3, 2, 1]);
=> 1
Ramda 也有一个_.last
函数
R.last(['fi', 'fo', 'fum']); //=> 'fum'
【讨论】:
【参考方案8】:这行得通:
array.reverse()[0]
【讨论】:
请解释你的代码在做什么。 欢迎来到 Stack Overflow!虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性 cmets 挤满你的代码,因为这会降低代码和解释的可读性! 其实很不错的想法。 Javascriptreverse()
做你所期望的,最后一项成为你可以通过[0]
解决的第一项。它是所有浏览器都可用的本机功能,因此速度在这里应该不是问题。 警告:developer.mozilla.org/en/docs/Web/JavaScript/Reference/… 说它正在改变数组。所以进一步访问反向数组可能不是你所期望的!
除了改变数组,这也会非常慢。
@svarog 这只会增加答案的时间复杂性。不必要的慢。【参考方案9】:
如果你使用的是 ES6,你可以这样做:
const arr = [ 1, 2, 3 ];
[ ...arr ].pop(); // 3
arr; // [ 1, 2, 3 ] (wasn't changed)
【讨论】:
How slow is that? 这和Array.prototype.slice(arr).pop();
一样,纯粹是为了得到最后一个元素而复制整个数组。
看起来很短,但与其他方法相比肯定慢【参考方案10】:
所以,很多人都在回答 pop(),但他们中的大多数人似乎没有意识到这是一种破坏性的方法。
var a = [1,2,3]
a.pop()
//3
//a is now [1,2]
所以,对于一个非常愚蠢的非破坏性方法:
var a = [1,2,3]
a[a.push(a.pop())-1]
//3
一种流行音乐,就像 90 年代一样 :)
push 将一个值附加到数组的末尾,并返回结果的长度。所以
d=[]
d.push('life')
//=> 1
d
//=>['life']
pop 在删除该索引处的值之前返回数组的最后一项的值。所以
c = [1,2,1]
c.pop()
//=> 1
c
//=> [1,2]
数组的索引为 0,因此 c.length => 3, c[c.length] => 未定义(因为如果您这样做,您正在寻找第 4 个值(此深度级别适用于任何不幸的新手在这里结束))。
对于您的应用程序来说,可能不是最好的,甚至不是一个好的方法,比如流量、流失等等。但是对于遍历一个数组,将其流式传输到另一个数组,只是愚蠢地使用低效的方法,this。完全是这样。
【讨论】:
“所以,很多人都用 pop() 来回答,但他们中的大多数人似乎没有意识到这是一种破坏性的方法。”实际上,他们都意识到这是一种破坏性的方法。您引用的答案以粗体清楚地说明了这一点,而涉及 pop 的所有其他答案都会首先复制数组。【参考方案11】:您可以在Array.prototype
上定义getter:
if (!Array.prototype.hasOwnProperty("last"))
Object.defineProperty(Array.prototype, "last",
get()
return this[this.length - 1];
);
console.log([9, 8, 7, 6].last); // => 6
如您所见,访问看起来不像函数调用; getter 函数在内部调用。
【讨论】:
修改不属于你的对象的原型是不好的做法。【参考方案12】:如果这对您的应用程序至关重要,请使用 JavaScript 对象。您不应该使用原始原语来管理应用程序的关键部分。由于这似乎是您的应用程序的核心,您应该改用对象。我在下面编写了一些代码来帮助您入门。 lastLocation
方法将返回最后一个位置。
function User(id)
this.id = id;
this.locations = [];
this.getId = function()
return this.id;
;
this.addLocation = function(latitude, longitude)
this.locations[this.locations.length] = new google.maps.LatLng(latitude, longitude);
;
this.lastLocation = function()
return this.locations[this.locations.length - 1];
;
this.removeLastLocation = function()
return this.locations.pop();
;
function Users()
this.users = ;
this.generateId = function()
return Math.random();
;
this.createUser = function()
var id = this.generateId();
this.users[id] = new User(id);
return this.users[id];
;
this.getUser = function(id)
return this.users[id];
;
this.removeUser = function(id)
var user = this.getUser(id);
delete this.users[id];
return user;
;
var users = new Users();
var user = users.createUser();
user.addLocation(0, 0);
user.addLocation(0, 1);
【讨论】:
我正在尝试使用它来重组我的程序。我是 JS 新手,但这比我目前拥有的要干净得多。你能解释一下吗?就像我要从数据库中提取坐标和用户 ID,我将如何触发程序?我正在使用 AJAX 继续调用从我的数据库中提取坐标的程序。 原语适用于简单的操作。并非所有地方都需要 OO。 这是一种正确的方法。对象倾向于使代码清晰易用。但是这里出了点问题:你没有使用原型来定义你的函数。这对性能不利,在定义函数时始终使用原型属性。每次创建此对象时,都会“即时”添加其他功能。 “您不应该使用原始原语来管理应用程序的关键部分。”这里的理由是什么? @LeviMorrison 好吧,我想这是一个观点。虽然我不同意。我参加的编程语言课程强调了函数式编程语言倾向于对原语、集合/列表和字典进行操作。这工作得很好,并且考虑到 JS 更像是一种功能语言而不是 OO 语言,我认为没有必要仅仅为了满足某人对编程的普遍看法而引入“对象”【参考方案13】:var last = function( obj, key )
var a = obj[key];
return a[a.length - 1];
;
last(loc, 'f096012e-2497-485d-8adb-7ec0b9352c52');
【讨论】:
@LeviMorrison:在这种情况下,您也可以在Array
的原型中添加一个方法。
@LeviMorrison:请参阅我的答案,了解向所有数组添加新方法的方式,因此获取最后一个元素更容易。
拥有像这个答案这样的*** fn 比向原型添加方法要好,因为它不会掩盖通过封装进行的访问。以上是关于选择JavaScript数组中的最后一个元素[重复]的主要内容,如果未能解决你的问题,请参考以下文章