Как получить доступ к массиву по кругу в JavaScript

У меня есть массив типа [A,B,C,D]. Я хочу получить доступ к этому массиву в цикле for, например

var arr = [A,B,C,D];

var len = arr.len;
for(var i = 0;i<arr.len;i++){
    0 - A,B,C
    1 - B,C,D
    2 - C,D,A
    3 - D,A,B
}

Я хочу получить доступ к этому, как в JavaScript, есть идеи?


person Anshul    schedule 05.07.2013    source источник


Ответы (6)


Попробуй это:

var arr = ["A","B","C","D"];
for (var i=0, len=arr.length; i<len; i++) {
    alert(arr.slice(0, 3).join(","));
    arr.push(arr.shift());
}

Без изменения массива было бы

for (var i=0, len=arr.length; i<len; i++) {
    var str = arr[i];
    for (var j=1; j<3; j++)
        str += ","+arr[(i+j)%len]; // you could push to an array as well
    alert(str);
}
// or
for (var i=0, len=arr.length; i<len; i++)
    alert(arr.slice(i, i+3).concat(arr.slice(0, Math.max(i+3-len, 0)).join(","));
person Bergi    schedule 05.07.2013

Отвечая на главный вопрос, кто-то может получить доступ к массиву циклическим способом, используя модульную арифметику. Этого можно достичь в JavaScript с помощью оператора модуля (%) и обходного пути.

Учитывая массив arr длины n и хранящееся в нем значение val, которое будет получено с помощью индекса доступа i, циклический и более безопасный способ доступа к массиву, независимо от значения и знака i, будет следующим:

let val = arr[(i % n + n) % n];

Этот небольшой трюк необходим — кто-то не может использовать результат модуля прямо — потому что JavaScript всегда оценивает операцию модуля как остаток от деления между делимым (первый операнд) и делителем (второй операнд), не учитывая их знаки, но присваивая остаток - знак делимого. Такое поведение не всегда приводит к желаемому эффекту "обхода" модульной арифметики и может привести к неправильному доступу к отрицательной позиции массива.

Ссылки для получения дополнительной информации:

  1. https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/what-is-modular-arithmetic
  2. https://en.wikipedia.org/wiki/Modular_arithmetic
  3. https://en.wikipedia.org/wiki/Modulo_operation
  4. https://dev.to/maurobringolf/a-neat-trick-to-compute-modulo-of-negative-numbers-111e
person wwgoncalves    schedule 29.01.2019
comment
ХОРОШО. Но это не обеспечивает циклический срез исходного массива. Это также не работает с отрицательными числами; например [1,2,3] start = 1,` len = -3` =› [2,1,3]. - person Garrett; 02.02.2021
comment
Я не понимаю. (Отрицательное число в качестве длины массива?) Не могли бы вы перефразировать то, что вы пытаетесь указать? - person wwgoncalves; 04.02.2021
comment
Почему бы не просто let val = arr[Math.abs(i % n)]; ? - person Mkdgs; 05.02.2021
comment
К сожалению, это не сработает для отрицательных значений i. Результат — остаток от деления — будет отличаться от результата, ожидаемого от модульной арифметики. Например, в JS (-1 % 10 + 10) % 10 оценивается как 9, а Math.abs(-1 % 10) оценивается как 1. - person wwgoncalves; 10.02.2021

Просто используя оператор модуля, вы можете обращаться к массиву по кругу.

var arr = ['A', 'B', 'C', 'D'];

for (var i = 0, len = arr.length; i < len; i++) {
  for (var j = 0; j < 3; j++) {
    console.log(arr[(i + j) % len])
  }
  console.log('****')
}

person user1948585    schedule 03.09.2014

как насчет этого однострочника, который я сделал?

var nextItem = (list.indexOf(currentItem) < list.length - 1)
                        ? list[list.indexOf(currentItem) + 1] : list[0];
person DanteTheSmith    schedule 31.03.2016

Однолинейное решение для циклического смещения «на месте»:

const arr = ["A","B","C","D"];
arr.forEach((x,i,t) => {console.log(i,t); t.push(t.shift());});
console.log("end of cycle", arr); // control: cycled back to the original

журналы:

0 Array ["A", "B", "C", "D"]
1 Array ["B", "C", "D", "A"]
2 Array ["C", "D", "A", "B"]
3 Array ["D", "A", "B", "C"]
"end of cycle" Array ["A", "B", "C", "D"]

Если вам нужны только первые 3 элемента, используйте:

arr.forEach((x,i,t) => {console.log(i,t.slice(0, 3)); t.push(t.shift());});
person allez l'OM    schedule 22.01.2019
comment
Как вы думаете, Циркулярный список — это способ решить этот вопрос? stackoverflow.com/questions/62238342/ - person João Ramires; 07.06.2020
comment
@JoãoRamires Вы должны использовать getTime/setTime для своего вопроса. Смотрите мой ответ там stackoverflow.com/questions/62238342/ - person allez l'OM; 08.06.2020
comment
Этот подход создает массив для каждой смены. Что, если бы существовала такая функция, как slice, которая оборачивается и принимает длину, например array.cirSlice(start, len). [1,3,4].cirSlice(3,5) результаты [4,1,3,4,1]? - person Garrett; 03.03.2021

Другие решения:

    var arr = ['A','B','C','D'];
    var nextVal = function (arr) {        
        return arr[( ( ( nextVal.counter < ( arr.length - 1 ) ) ? ++nextVal.counter : nextVal.counter=0  )   )];
    };

    for(var i=0;i<arr.length;i++){
        console.log(nextVal(arr)+','+nextVal(arr)+','+nextVal(arr));
    }

И на основе модуля:

var arr = ['A','B','C','D'];
var len = arr.length;

var nextVal = function (arr, dir = 1) { 
        if ( dir < 0 ) { nextVal.counter--;}
        let i = (nextVal.counter % len + len) % len;  
        if ( dir > 0 ) { nextVal.counter++; }
        return arr[i];
};

nextVal.counter=0;
for(var i=0;i<arr.length;i++){
    console.log(nextVal(arr)+','+nextVal(arr)+','+nextVal(arr));
}

// in reverse 
console.log('-------------------');
nextVal.counter=0;
for(var i=0; i<10; i++) {
    console.log(nextVal(arr, -1)+','+nextVal(arr, -1)+','+nextVal(arr, -1));
}

person Mkdgs    schedule 05.02.2021