【问题标题】:JavaScript move an item of an array to the frontJavaScript 将数组中的一项移到最前面
【发布时间】:2014-07-18 06:29:51
【问题描述】:

我想检查一个数组是否包含"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"]

我该如何解决这个问题?

【问题讨论】:

  • Remove item from array by value 的可能重复项
  • @jraede:当然有效?
  • remove 方法是什么?你使用的是 Prototype.js 还是类似的东西?
  • if('role' in data)data.remove()?

标签: javascript arrays


【解决方案1】:

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

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

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

【讨论】:

  • 这可能会改变其他项目的顺序,sort 不稳定。
  • @Bergi:好点,这是需要考虑的事情。这取决于实现,似乎大多数浏览器都有稳定的排序:stackoverflow.com/questions/3026281/…
  • 有效,但嵌套第三级使得代码相当难以理解
  • 除了“角色”之外,还有没有可能对剩余元素进行排序
  • 只是想指出,如果你用谷歌搜索这个 JS fiddle 链接,你会发现它在互联网上非常流行。谢谢,这对我很有帮助。
【解决方案2】:

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

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

【讨论】:

  • 这会忘记检查角色是否在重新添加之前从列表中删除。
【解决方案3】:

我的第一个想法是:

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');
}

参考资料:

【讨论】:

  • 我认为我们可以通过不必使用Array.indexOf() 函数两次来使这更好一点,因为这意味着它会搜索整个数组两次。 ``` const roleIndex = data.indexOf('role'); if (roleIndex > 0) { data.splice(roleIndex, 1); data.unshift('角色'); } ```
  • 比排序更合理。
  • data.splice 返回刚刚删除的部分,您可以立即使用它来插入,使其成为 1 行而不是 2 行,并且还使其适用于更复杂的情况,例如对象数组:@987654331 @
【解决方案4】:
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]

【讨论】:

  • 这是迄今为止最好的答案,因为它依赖于索引而不是值。因此,对于希望依赖索引和希望依赖值的人(他们可以简单地将 index 替换为 data.findIndex(value)),它都很有用。
【解决方案5】:

如果你不想改变现有的数组,你可以使用 ES6 解构和 filter 方法来创建一个新的副本,同时保持其他项的顺序。

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

【讨论】:

  • 这会忘记检查角色是否在重新添加之前从列表中删除。
【解决方案6】:

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

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

【讨论】:

  • 如果没有等于“角色”的元素怎么办?在这种情况下,您会将 undefined 作为数组的第一个元素。
  • 你说得对,在这篇文章中,他使用:if ("role" in data),然后将“角色”推到首位。我的回答并不彻底,但它隐含地要求在之前进行检查(否则我们不会更新数组)
  • 谢谢,这在函数式编程纯度方面更好。如果有多个具有“角色”的元素,则添加另一件事,该解决方案将仅返回顶部的第一个,因为 find 函数返回仅一个元素。一个通用的解决方案可能是:const sortedCards = [...data.filter((item) => item === 'NORI'),...cards.filter((item) => item !== 'NORI')];
【解决方案7】:

如果你有一个对象数组,你可以通过拼接和推送来移动起始索引。 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);

【讨论】:

  • 这一行到底是做什么的:friends.push(...friends.splice(0, tomsIndex));
【解决方案8】:

要检查数组中是否存在项目,您应该使用.includes() 而不是in(正如这里已经指出的,in 用于对象中的属性)。

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

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

【讨论】:

  • 你听说过clean-code吗?真的,我不明白为什么人们对变量名和参数使用缩写......
  • 在不了解底层代码的情况下复制/粘贴时选择的文本略少
【解决方案9】:

我会选择这个 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' ]

【讨论】:

    【解决方案10】:

    您可以将支票的增量与想要的值放在顶部。

    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没有有稳定的排序算法。
    • Edge 从 79 版本开始支持稳定排序!
    【解决方案11】:

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

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

    可以这样使用

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

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

    【讨论】:

      【解决方案12】:
      1. in 运算符是关于属性的,而不是关于数组中的项。请参阅 How do I check if an array includes an object in JavaScript? 了解其他用途。
      2. 您的 if 块中的两个 (!) 语句缺少大括号
      3. 我不确定您正在使用的 .remove() 函数是否需要一个项目的索引。

      【讨论】:

        【解决方案13】:
        var data= ["email","role","type","name"];
        
        data.splice(data.indexOf("role"), 1);
        data.unshift('role');
        

        【讨论】:

        • 如果原始数组不包含"role",则无法正常工作。
        【解决方案14】:

        一个可重用的 ES6/Typescript 解决方案:

        const moveToStart = <T>(array: T[], predicate: (item: T) => boolean): T[] => {
          return array.sort((a, b) => {
            if (predicate(a)) return -1;
            if (predicate(b)) return 1;
        
            return 0;
          });
        };
        
        const data = ["email", "role", "type", "name"];
        const result = moveToStart(data, (item) => item === "role"))
        

        【讨论】:

          【解决方案15】:

          使用 lodash _.sortBy。如果项目为role,则将其排在第一位,否则排在第二位。如果没有role

          ,这也可以正常工作

          var data = ["email", "role", "type", "name"];
          
          var sorted = _.sortBy(data, function(item) {
            return item === 'role' ? 0 : 1;
          });
          
          console.log(sorted);
          &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"&gt;&lt;/script&gt;

          【讨论】:

            【解决方案16】:

            只是想把它放在这里,因为根据其他 cmets Guffa 的答案似乎正在获得牵引力,最后的第三级 - 这是该答案的否定 cmets 之一是不必要的。也使用箭头函数使它看起来更干净。

            此外,它很容易扩展到处理对象数组。

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

            我相信这也应该解决阵列其余部分受到影响的担忧。当 sort 函数返回小于 0 的数字(first === x)时,元素会向 Array 的开头移动,当它返回 0(first !== y)时,不会移动,而当 a大于 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);
            

            【讨论】:

              【解决方案17】:

              广义单行:

              const data = ["a", "b", "c", "d", "e", "f"];
              const [from, take] = [3, 2];
              
              data.unshift(...data.splice(from, take));
              // alternatively
              data = [...data.splice(from, take), ...data];
              // ["d", "e", "a", "b", "c", "f"]
              

              【讨论】:

                【解决方案18】:

                const moveToFront = (arr, queryStr) =>
                  arr.reduce((acc, curr) => {
                    if (queryStr === curr) {
                      return [curr, ...acc];
                    }
                    return [...acc, curr];
                  }, []);
                
                const data = ['email', 'role', 'type', 'name'];
                
                console.log(moveToFront(data, 'role'))

                【讨论】:

                  【解决方案19】:
                  const moveTargetToBeginningOfArray = (arr, target) => {
                      // loop through array
                      for (let i = 0; i < arr.length; i++){
                          // if current indexed element is the target
                          if(arr[i] === target){
                              // remove that target element
                              arr.splice(i, 1)
                              // then add a target element to the beginning of the array
                              arr.unshift(target)
                          }
                      }
                      return arr;
                  };
                  
                  // quick sanity check, before and after both are correct
                  const arrayOfStrings = ["email", "role", "type", "name", "role", "role"];
                  console.log('before:', arrayOfStrings)
                  console.log('after:', moveTargetToBeginningOfArray(arrayOfStrings, "role"))
                  
                  // this would also work for numbers
                  var arrayOfNumbers = [2,4,0,3,0,1,0]
                  console.log('before:', arrayOfNumbers)
                  console.log('after:', moveTargetToBeginningOfArray(arrayOfNumbers, 0))
                  

                  【讨论】:

                  • 另外,只需将单词“unshift”更改为“push”,就很容易将目标放在数组的末尾
                  【解决方案20】:
                  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() 的第一个参数指定开始删除元素的索引,第二个参数指定要删除的参数数量。

                  【讨论】:

                  • 当然应该使用它。只需为那些(死)浏览器填充它。
                  【解决方案21】:

                  data.unshift(data.splice(data.indexOf('role'), 1)[0])

                  data.indexOf('role')会在数组中找到'role'的索引,然后拼接原始数组去除'role'元素,使用unshift添加到数组的开头

                  【讨论】:

                    【解决方案22】:
                    var data= ["email","role","type","name"];
                    if ("role" in data) data.splice(data.indexOf("role"),1); data.unshift("role");
                    data;
                    

                    【讨论】:

                    • 这与问题中的问题相同,并给出相同的错误结果。 “in”运算符不适用于数组,并且您在多个旨在由“if”语句条件化的语句周围缺少花括号。
                    猜你喜欢
                    • 2014-08-07
                    • 2021-05-15
                    • 2014-08-26
                    • 2016-04-16
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-10-05
                    • 1970-01-01
                    相关资源
                    最近更新 更多