JavaScript переміщує елемент масиву вперед


78

Я хочу перевірити, чи містить масив "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: Звичайно, це дійсно?
Бергі

Що це за removeметод? Ви використовуєте Prototype.js або щось подібне?
Бергі

if('role' in data)і data.remove()?
jraede

Відповіді:


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: Хороша думка, це щось розглянути. Це залежить від конкретної реалізації, і, здається , більшість браузерів мають стабільний сорт: stackoverflow.com/questions/3026281 / ...
Guffa

5
Працює, але вкладання третини робить досить важким для розуміння код
Валтарі

Чи є можливість сортувати інші елементи, крім "ролі"
Jeya Suriya Muthumari

Тільки хочу зазначити, що якщо погуглити це скриптове посилання JS, ви побачите, що воно стало справді популярним в Інтернеті. Дякую, це мені справді допомогло.
Нікіта Фукс,

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'); if (roleIndex> 0) {data.splice (roleIndex, 1); data.unshift ('роль'); } `` `
Аріелла

1
Це більш розумно, ніж сортування.
MajidTaheri

data.spliceповертає щойно видалену частину, яку ви можете відразу використовувати, щоб вставити, зробивши її 1 рядком замість 2, а також зробивши це корисним для більш складних випадків, таких як для масиву об'єктів:data.unshift(data.splice(roleIndex, 1)[0])
Максим Георгієвський,

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
Це, безумовно, найкраща відповідь тут, оскільки вона спирається на індекс, а не на значення. Тож це корисно як для тих, хто бажає покластися на індекс, так і для тих, хто хоче покластися на значення (який може просто замінити indexна data.findIndex(value)).
goodvibration

17

Якщо ви не хочете змінювати існуючий масив, ви можете використовувати ES6 деструктуризацію з методом фільтра, щоб створити нову копію, зберігаючи порядок інших елементів.

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першим елементом масиву.
Jan Jůna

Ви маєте рацію, у цій публікації він використовує: if ("role" in data)перед тим, як висунути "роль" на перше місце. Мій відповідь не був ретельний , але неявно запитує перевірку перед ( в іншому випадку ми не будемо оновлювати масив)
Maldoror

5

Якщо у вас є масив об’єктів, ви можете зрушити індекс початку за допомогою сплайсингу та натискання. Зрощування замінює вихідний масив частиною масиву, починаючи з потрібного індексу, і повертає ту частину, яку він видаляє (матеріали перед індексом), яку ви натискаєте.

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
  1. inоператор про властивості, а нема про предметах , в масивах. Див. Як перевірити, чи містить масив об’єкт у JavaScript? для чого використовувати ще.
  2. Вам бракує фігурних дужок навколо двох (!) Операторів у вашому блоці if-block
  3. Я не впевнений, чи ця .remove()функція, яку ви використовуєте, бере індекс елемента.


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


Це може призвести до несподіваних результатів, оскільки ECMAScript до 2019 року не вимагав Array#sortстабільності. Згідно з MDN , Internet Explorer та Edge не мають стабільного алгоритму сортування.
вул.

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

Просто хотів залишити це тут, оскільки, згідно з іншими коментарями, відповідь Гуффи, схоже, набирає популярності, остаточний третій рівень - що було одним із негативних коментарів до цієї відповіді непотрібний. Також використання функцій стрілок робить його набагато чистішим.

Крім того, його легко розширити для обробки масивів об'єктів.

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

Я вважаю, що це також повинно впоратись з турботою щодо решти масиву, на який впливає. Коли функція сортування повертає число менше 0 (перший === x), елемент рухатиметься до початку масиву, коли поверне 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
Звичайно, вам слід це використовувати. Просто обробіть це для тих (мертвих) браузерів.
Бергі

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

Це має ті самі проблеми, що й у питанні, і дає той самий неправильний результат. Оператор "in" не застосовується до масивів, і вам бракує фігурних дужок навколо кількох операторів, призначених для кондиціонування оператором "if".
Ден Корн,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.