JavaScript将数组的项移到最前面


77

我想检查数组是否包含"role"。如果是这样,我想将移到"role"数组的前面。

var data= ["email","role","type","name"];
if ("role" in data) data.remove(data.indexOf("role")); data.unshift("role")
data;

在这里,我得到了结果:

["role", "email", "role", "type", "name"]

我怎样才能解决这个问题?



2
@jraede:当然有效吗?
Bergi 2014年

那是什么remove方法?您是否正在使用Prototype.js或类似的东西?
Bergi 2014年

if('role' in data)data.remove()
jraede 2014年

Answers:


80

您可以对数组进行排序,并指定该值位于"role"所有其他值之前,并且所有其他值均相等:

var first = "role";
data.sort(function(x,y){ return x == first ? -1 : y == first ? 1 : 0; });

演示:http//jsfiddle.net/Guffa/7ST24/


15
这可能会改变其他项目的顺序,但sort不稳定。
Bergi 2014年

@Bergi:好点,这是要考虑的事情。这是依赖于实现,它似乎大多数浏览器有一个稳定的排序:stackoverflow.com/questions/3026281/...
Guffa

4
可行,但嵌套第三层会使代码难以理解
Waltari

是否有任何可能比“角色”之外的其余元素进行排序
Jeya素里亚Muthumari

只是要注意,如果您搜索此JS小提琴链接,您会看到它在Internet上非常流行。谢谢,这真的帮助了我。
Nikita Fuchs

67

我认为ES6中最干净的解决方案是:

let data = ["email","role","type","name"];
data = data.filter(item => item !== "role");
data.unshift("role");

57

我的第一个想法是:

var data= ["email","role","type","name"];

// if it's not there, or is already the first element (of index 0)
// then there's no point going further:
if (data.indexOf('role') > 0) {
    // find the current index of 'role':
    var index = data.indexOf('role');
    // using splice to remove elements from the array, starting at
    // the identified index, and affecting 1 element(s):
    data.splice(index,1);
    // putting the 'role' string back in the array:
    data.unshift('role');
}

console.log(data);

修改并整理一下:

if (data.indexOf('role') > 0) {
    data.splice(data.indexOf('role'), 1);
    data.unshift('role');
}

参考文献:


10
我认为我们可以通过不必Array.indexOf()两次使用该函数来使它更好一些,因为这意味着它将对整个数组进行两次搜索。``const roleIndex = data.indexOf('role'); 如果(roleIndex> 0){data.splice(roleIndex,1); data.unshift('role'); }`
Ariella

1
比排序更合理。
MajidTaheri

data.splice返回刚删除的部分,您可以立即使用它插入,使其成为1行而不是2行,并且还使其对更复杂的情况(如对象数组)很有用:data.unshift(data.splice(roleIndex, 1)[0])
Maxim Georgievskiy

39
let data = [0, 1, 2, 3, 4, 5];
let index = 3;
data.unshift(data.splice(index, 1)[0]);
// data = [3, 0, 1, 2, 4, 5]

4
到目前为止,这是最好的答案,因为它依赖于索引而不是值。因此,这对于希望依赖索引的人和希望依赖值的人(可以简单地替换indexdata.findIndex(value))都是有用的。
goodvibration

17

如果您不想更改现有数组,则可以将ES6解构与filter方法一起使用,以创建新副本,同时保持其他项目的顺序。

const data = ["email", "role", "type", "name"];
const newData = ['role', ...data.filter(item => item !== 'role')];

13

如果需要,这是一个不变的解决方案:

      const newData = [
          data.find(item => item === 'role'),
          ...data.filter(item => item !== 'role'),
        ],

如果没有元素等于“角色”怎么办?在这种情况下,您将拥有undefined数组的第一个元素。
JanJůna'9

没错,他在这篇文章中使用了:if ("role" in data)在将“角色”推到第一位之前。我的回答不彻底,但隐式要求在此之前进行检查(否则我们将不更新数组)
Maldoror

5

如果您有一个对象数组,则可以通过拼接和推动来移动起始索引。Splice用所需索引开始的数组部分替换原始数组,并返回您删除的部分(索引之前的内容)。

let friends = [{
    id: 1,
    name: "Sam",
  },
  {
    id: 2,
    name: "Steven",
  },
  {
    id: 3,
    name: "Tom",
  },
  {
    id: 4,
    name: "Nora",
  },
  {
    id: 5,
    name: "Jessy",
  }
];

const tomsIndex = friends.findIndex(friend => friend.name == 'Tom');
friends.push(...friends.splice(0, tomsIndex));

console.log(friends);


4

要检查数组中是否存在某项,应使用.includes()而不是in(如此处已指出的,in是针对对象中的属性的)。

此功能可满足您的需求:(将项目从其所在位置移走并从前面读取)

   data = ["email","role","type","name"];
   moveToFirst("role", data)
    
   function moveToFirst(s, r){
      if (r.includes(s)){
        r.splice(r.indexOf(s),1);
        r.unshift(s);
      } 
    }
    
    console.log(data)


3

我会选择此ES6解决方案。它不会改变原始数组(考虑到它不是嵌套的),不会遍历该数组(过滤器),并且您不仅仅限于第0个用于移动数组项的索引。

const moveArrayItem = (array, fromIndex, toIndex) => {
    const arr = [...array];
    arr.splice(toIndex, 0, ...arr.splice(fromIndex, 1));
    return arr;
}


const arr = ["a", "b", "c", "d", "e", "f", "g"];
console.log(moveArrayItem(arr, 4, 0))
// [ 'e', 'a', 'b', 'c', 'd', 'f', 'g' ]



2

类似于@Tandroid的答案,但更通用的解决方案:

const putItemsFirst = ({ findFunction, array }) => [
    ...array.filter(findFunction), 
    ...array.filter(signer => !findFunction(signer)),
]; 

可以这样使用

putItemsFirst({ 
    array: ["email","role","type","name"], 
    findFunction: item => item === 'role',
})

我最终使用了与此类似的东西,


1

您可以将支票的差额放在期望值的顶部。

var data = ["email", "role", "type", "name"];

data.sort((a, b) => (b === 'role') - (a === 'role'));

console.log(data);


这可能会导致意外结果,因为2019年之前的ECMAScript不需要Array#sort保持稳定。根据MDN的说法,Internet Explorer和Edge没有稳定的排序算法。
str

Edge从79版开始支持稳定排序!
艾萨克·格林斯汀

0

使用lodash _.sortBy。如果项目是role,则将首先对其进行排序,否则将对其进行排序。如果没有,这也很好role

var data = ["email", "role", "type", "name"];

var sorted = _.sortBy(data, function(item) {
  return item === 'role' ? 0 : 1;
});

console.log(sorted);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>


0

只是想将其放在此处,因为根据其他评论,古法(Guffa)的答案似乎越来越受到关注,最后的高等教育-这是对该答案的负面评论之一是没有必要的。还使用箭头功能使其看起来更整洁。

而且,它很容易扩展以处理对象数组。

const first = "role";
data.sort((x, y) => first === x ? -1 : first === y)

我相信这也应该解决阵列其余部分受到影响的担忧。当sort函数返回的数字小于0(第一个=== x)时,元素将朝Array的开头移动;当返回0(第一个=== y)时,元素将不移动;当如果数字大于0(第一个=== y),则x将相对于x和y向数组的结尾移动。因此,当x或y都不等于所需的第一个元素(或在对对象进行排序时为标识符)时,两者将不会相对移动。

对于对象:

const unsorted = [{'id': 'test'}, {'id': 'something'}, {'id': 'else'}];
const first = 'something';
const sorted = unsorted.sort((x,y) => x['id'] === first ? -1 : y['id'] === first);

-1
var i = -1;
while (i < data.length) {
    if (data[i] === "role") {
        data.splice(i, 1);
        break;
    }
    i++;
}
data.unshift("role");

indexOf仅具有有限的浏览器支持,未被IE7-8识别。因此,即使我是您,也不会使用它,即使牺牲了几行代码的简洁性也是如此。您还想在“ unshift”语句的末尾加上分号。splice()的第一个参数指定开始删除元素的索引,第二个参数指定要删除的参数数目。


2
当然应该使用它。只需为那些(死的)浏览器填充即可。
Bergi 2014年

-4
var data= ["email","role","type","name"];
if ("role" in data) data.splice(data.indexOf("role"),1); data.unshift("role");
data;

这有与问题相同的问题,并且给出了相同的错误结果。“ in”运算符不适用于Array,并且您缺少多个打算由“ if”语句条件化的语句的花括号。
丹·科恩,2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.