Переместить элемент в массив строк на передний план? [Дубликат]

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

Код печатает двоичное представление поплавков в 3 отдельных группах

SIGN EXPONENT FRACTION

, и после этого он печатает сумму, которая при суммировании с достаточной точностью покажет значение, которое действительно существует в аппаратном обеспечении.

Поэтому, когда вы пишете float x = 999... компилятор преобразует это число в битовое представление, напечатанное функцией xx, так что сумма, напечатанная функцией yy, будет равна заданному числу.

В действительности эта сумма является только приближение. Для числа 999,999,999 компилятор будет вставлять в бит представление float число 1,000,000,000

После кода я присоединяю консольный сеанс, в котором я вычисляю сумму терминов для обеих констант (минус PI и 999999999) который действительно существует в аппаратном обеспечении, вставленном там компилятором.

#include <stdio.h>
#include <limits.h>

void
xx(float *x)
{
    unsigned char i = sizeof(*x)*CHAR_BIT-1;
    do {
        switch (i) {
        case 31:
             printf("sign:");
             break;
        case 30:
             printf("exponent:");
             break;
        case 23:
             printf("fraction:");
             break;

        }
        char b=(*(unsigned long long*)x&((unsigned long long)1<<i))!=0;
        printf("%d ", b);
    } while (i--);
    printf("\n");
}

void
yy(float a)
{
    int sign=!(*(unsigned long long*)&a&((unsigned long long)1<<31));
    int fraction = ((1<<23)-1)&(*(int*)&a);
    int exponent = (255&((*(int*)&a)>>23))-127;

    printf(sign?"positive" " ( 1+":"negative" " ( 1+");
    unsigned int i = 1<<22;
    unsigned int j = 1;
    do {
        char b=(fraction&i)!=0;
        b&&(printf("1/(%d) %c", 1<<j, (fraction&(i-1))?'+':')' ), 0);
    } while (j++, i>>=1);

    printf("*2^%d", exponent);
    printf("\n");
}

void
main()
{
    float x=-3.14;
    float y=999999999;
    printf("%lu\n", sizeof(x));
    xx(&x);
    xx(&y);
    yy(x);
    yy(y);
}

Вот сеанс консоли, в котором я вычисляю реальное значение float, которое существует в аппаратном обеспечении. Я использовал bc для печати суммы терминов, выводимых основной программой. Можно вставить эту сумму в python repl или что-то подобное.

-- .../terra1/stub
@ qemacs f.c
-- .../terra1/stub
@ gcc f.c
-- .../terra1/stub
@ ./a.out
sign:1 exponent:1 0 0 0 0 0 0 fraction:0 1 0 0 1 0 0 0 1 1 1 1 0 1 0 1 1 1 0 0 0 0 1 1
sign:0 exponent:1 0 0 1 1 1 0 fraction:0 1 1 0 1 1 1 0 0 1 1 0 1 0 1 1 0 0 1 0 1 0 0 0
negative ( 1+1/(2) +1/(16) +1/(256) +1/(512) +1/(1024) +1/(2048) +1/(8192) +1/(32768) +1/(65536) +1/(131072) +1/(4194304) +1/(8388608) )*2^1
positive ( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
-- .../terra1/stub
@ bc
scale=15
( 1+1/(2) +1/(4) +1/(16) +1/(32) +1/(64) +1/(512) +1/(1024) +1/(4096) +1/(16384) +1/(32768) +1/(262144) +1/(1048576) )*2^29
999999999.999999446351872

Вот и все. Фактически значение 999999999

999999999.999999446351872

Вы также можете проверить с помощью bc, что -3.14 также возмущено. Не забудьте установить коэффициент scale в bc.

Отображаемая сумма - это то, что внутри аппаратного обеспечения. Значение, которое вы получаете, вычисляя его, зависит от установленного вами масштаба. Я установил коэффициент scale равным 15. Математически, с бесконечной точностью, кажется, что это 1 000 000 000.

360
задан robsch 8 March 2016 в 11:08
поделиться

19 ответов

Если вы хотите версию на npm, array-move является ближайшим к этому ответу, хотя это не та же реализация. Дополнительную информацию см. В разделе использования. Предыдущая версия этого ответа (модифицированного Array.prototype.move) может быть найдена на npm в array.prototype.move .


У меня был довольно хороший успех с эта функция:

function array_move(arr, old_index, new_index) {
    if (new_index >= arr.length) {
        var k = new_index - arr.length + 1;
        while (k--) {
            arr.push(undefined);
        }
    }
    arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
    return arr; // for testing
};

// returns [2, 1, 3]
console.log(array_move([1, 2, 3], 0, 1)); 

Обратите внимание, что последний return просто предназначен для тестирования: splice выполняет операции над массивом на месте, поэтому возврат не требуется. В дополнение, этот move является операцией на месте. Если вы хотите избежать этого и вернуть копию, используйте slice .

Выполняя код:

  1. Если new_index больше длины массива, мы хотим (я полагаю) правильно разместить массив с новыми undefined s. Этот небольшой фрагмент обрабатывает это, нажимая undefined на массив до тех пор, пока мы не получим правильную длину.
  2. Затем в arr.splice(old_index, 1)[0] мы соединим старый элемент. splice возвращает элемент, который был сращирован, но находится в массиве. В нашем примере выше это было [1]. Итак, мы берем первый индекс этого массива, чтобы получить там исходный 1.
  3. Затем мы используем splice для вставки этого элемента в место new_index. Поскольку мы добавили массив выше, если new_index > arr.length, он, вероятно, появится в нужном месте, если только они не сделали что-то странное, как передать отрицательное число.

Более благоприятная версия для учета отрицательных индексов:

function array_move(arr, old_index, new_index) {
    while (old_index < 0) {
        old_index += arr.length;
    }
    while (new_index < 0) {
        new_index += arr.length;
    }
    if (new_index >= arr.length) {
        var k = new_index - arr.length + 1;
        while (k--) {
            arr.push(undefined);
        }
    }
    arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
    return arr; // for testing purposes
};
    
// returns [1, 3, 2]
console.log(array_move([1, 2, 3], -1, -2));

Что должно учитывать такие вещи, как array_move([1, 2, 3], -1, -2) правильно (переместите последний элемент во второе и последнее место). Результат для этого должен быть [1, 3, 2].

В любом случае, в вашем исходном вопросе вы сделаете array_move(arr, 0, 2) для a после c. Для d до b вы сделали бы array_move(arr, 3, 1).

521
ответ дан Reid 26 August 2018 в 08:24
поделиться

Это основано на решении Рейда. За исключением:

  • Я не изменяю прототип Array.
  • Перемещение элемента из границ вправо не создает элементы undefined, оно просто перемещается

Функция:

function move(array, oldIndex, newIndex) {
    if (newIndex >= array.length) {
        newIndex = array.length - 1;
    }
    array.splice(newIndex, 0, array.splice(oldIndex, 1)[0]);
    return array;
}

Единичные тесты:

describe('ArrayHelper', function () {
    it('Move right', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 0, 1);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    })
    it('Move left', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, 0);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    });
    it('Move out of bounds to the left', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, -2);
        assert.equal(array[0], 2);
        assert.equal(array[1], 1);
        assert.equal(array[2], 3);
    });
    it('Move out of bounds to the right', function () {
        let array = [1, 2, 3];
        arrayHelper.move(array, 1, 4);
        assert.equal(array[0], 1);
        assert.equal(array[1], 3);
        assert.equal(array[2], 2);
    });
});
14
ответ дан André Pena 26 August 2018 в 08:24
поделиться

В итоге я объединил два из них, чтобы немного поработать, двигаясь как на большие, так и на большие расстояния. Я получаю довольно последовательные результаты, но это, вероятно, может быть немного изменено кем-то умнее меня, чтобы работать по-разному для разных размеров и т. Д.

Использование некоторых других методов при перемещении объектов на небольшие расстояния было значительно быстрее (x10), чем использование сплайсинга. Это может меняться в зависимости от длины массива, но это верно для больших массивов.

function ArrayMove(array, from, to) {
    if ( Math.abs(from - to) > 60) {
        array.splice(to, 0, array.splice(from, 1)[0]);
    } else {
        // works better when we are not moving things very far
        var target = array[from];
        var inc = (to - from) / Math.abs(to - from);
        var current = from;
        for (; current != to; current += inc) {
            array[current] = array[current + inc];
        }
        array[to] = target;    
    }
}

http://jsperf.com/arraymove-many-sizes

2
ответ дан Andrew Backer 26 August 2018 в 08:24
поделиться

Получил эту идею от @Reid, чтобы толкать что-то вместо места, которое должно быть перемещено, чтобы сохранить размер массива постоянным. Это упрощает вычисления. Кроме того, нажатие пустого объекта имеет дополнительные преимущества в том, что его можно искать по отдельности позже. Это работает, потому что два объекта не равны, пока они не обращаются к одному и тому же объекту.

({}) == ({}); // false

Итак, вот функция, которая берет в исходном массиве и указателях источника, целевых. Вы можете добавить его в Array.prototype, если необходимо.

function moveObjectAtIndex(array, sourceIndex, destIndex) {
    var placeholder = {};
    // remove the object from its initial position and
    // plant the placeholder object in its place to
    // keep the array length constant
    var objectToMove = array.splice(sourceIndex, 1, placeholder)[0];
    // place the object in the desired position
    array.splice(destIndex, 0, objectToMove);
    // take out the temporary object
    array.splice(array.indexOf(placeholder), 1);
}
14
ответ дан Anurag 26 August 2018 в 08:24
поделиться
    Array.prototype.moveUp = function (value, by) {
        var index = this.indexOf(value),
            newPos = index - (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos < 0)
            newPos = 0;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };

    Array.prototype.moveDown = function (value, by) {
        var index = this.indexOf(value),
            newPos = index + (by || 1);

        if (index === -1)
            throw new Error("Element not found in array");

        if (newPos >= this.length)
            newPos = this.length;

        this.splice(index, 1);
        this.splice(newPos, 0, value);
    };



    var arr = ['banana', 'curyWurst', 'pc', 'remembaHaruMembaru'];

    alert('withiout changes= '+arr[0]+' ||| '+arr[1]+' ||| '+arr[2]+' ||| '+arr[3]);
    arr.moveDown(arr[2]);


    alert('third word moved down= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);
    arr.moveUp(arr[2]);
    alert('third word moved up= '+arr[0] + ' ||| ' + arr[1] + ' ||| ' + arr[2] + ' ||| ' + arr[3]);

http://plnkr.co/edit/JaiAaO7FQcdPGPY6G337?p=preview

4
ответ дан Arthur 26 August 2018 в 08:24
поделиться

Я реализовал неизменяемое решение ECMAScript 6, основанное на ответе @Merc здесь:

const moveItemInArrayFromIndexToIndex = (array, fromIndex, toIndex) => {
  const newArray = [...array];

  if (fromIndex === toIndex) return newArray;

  const target = newArray[fromIndex];
  const inc = toIndex < fromIndex ? -1 : 1;

  for (let i = fromIndex; i !== toIndex; i += inc) {
    newArray[i] = newArray[i + inc];
  }

  newArray[toIndex] = target;

  return newArray;
};

Имена переменных могут быть сокращены, просто используются длинные, чтобы код может объяснить себя.

1
ответ дан Barry Michael Doyle 26 August 2018 в 08:24
поделиться

Во многих местах указывается ( добавление пользовательских функций в Array.prototype ), играя с прототипом Array, может быть плохой идеей, в любом случае я сочетал лучшее из разных сообщений, я пришел с этим, используя современный Javascript:

    Object.defineProperty(Array.prototype, 'immutableMove', {
        enumerable: false,
        value: function (old_index, new_index) {
            var copy = Object.assign([], this)
            if (new_index >= copy.length) {
                var k = new_index - copy.length;
                while ((k--) + 1) { copy.push(undefined); }
            }
            copy.splice(new_index, 0, copy.splice(old_index, 1)[0]);
            return copy
        }
    });

    //how to use it
    myArray=[0, 1, 2, 3, 4];
    myArray=myArray.immutableMove(2, 4);
    console.log(myArray);
    //result: 0, 1, 3, 4, 2

Надежда может быть полезна любому

0
ответ дан BernieSF 26 August 2018 в 08:24
поделиться

Я использовал хороший ответ @Reid , но боролся с перемещением элемента из конца массива на один шаг дальше - в начало (как в цикле). Например. ['a', 'b', 'c'] должны стать ['c', 'a', 'b'], вызвав .move (2,3)

. Я достиг этого, изменив case for new_index> = this.length.

Array.prototype.move = function (old_index, new_index) {
        console.log(old_index + " " + new_index);
        while (old_index < 0) {
            old_index += this.length;
        }
        while (new_index < 0) {
            new_index += this.length;
        }
        if (new_index >= this.length) {
            new_index = new_index % this.length;
        }
        this.splice(new_index, 0, this.splice(old_index, 1)[0]);
        return this; // for testing purposes
    };
1
ответ дан Community 26 August 2018 в 08:24
поделиться

В дополнение к отличный ответ Рида (и потому, что я не могу прокомментировать); Вы можете использовать modulo, чтобы сделать как отрицательные индексы, так и слишком большие индексы «перевернуться»:

function array_move(arr, old_index, new_index) {
  new_index =((new_index % arr.length) + arr.length) % arr.length;
  arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
  return arr; // for testing
}

// returns [2, 1, 3]
console.log(array_move([1, 2, 3], 0, 1)); 

0
ответ дан Didi 26 August 2018 в 08:24
поделиться

Вот один лайнер, который я нашел на JSPerf ....

Array.prototype.move = function(from, to) {
    this.splice(to, 0, this.splice(from, 1)[0]);
};

, который является замечательным для чтения, но если вы хотите, чтобы производительность (в небольших наборах данных) пыталась ...

 Array.prototype.move2 = function(pos1, pos2) {
    // local variables
    var i, tmp;
    // cast input parameters to integers
    pos1 = parseInt(pos1, 10);
    pos2 = parseInt(pos2, 10);
    // if positions are different and inside array
    if (pos1 !== pos2 && 0 <= pos1 && pos1 <= this.length && 0 <= pos2 && pos2 <= this.length) {
      // save element from position 1
      tmp = this[pos1];
      // move element down and shift other elements up
      if (pos1 < pos2) {
        for (i = pos1; i < pos2; i++) {
          this[i] = this[i + 1];
        }
      }
      // move element up and shift other elements down
      else {
        for (i = pos1; i > pos2; i--) {
          this[i] = this[i - 1];
        }
      }
      // put element from position 1 to destination
      this[pos2] = tmp;
    }
  }

Я не могу взять кредит, все должно пойти на Richard Scarrott . Он использует метод сплайсинга для меньших наборов данных в этом тесте производительности . Тем не менее он значительно медленнее на больших наборах данных , как указывает Дарвейн .

202
ответ дан digiguru 26 August 2018 в 08:24
поделиться

Один из подходов состоял в том, чтобы создать новый массив с фигурами в том порядке, в котором вы хотите, используя метод среза.

Пример

var arr = [ 'a', 'b', 'c', 'd', 'e'];
var arr2 = arr.slice(0,1).concat( ['d'] ).concat( arr.slice(2,4) ).concat( arr.slice(4) );
  • arr.slice (0,1) дает вам ['a']
  • arr.slice (2,4) дает вам ['b', 'c']
  • arr.slice (4 ) дает вам ['e']
7
ответ дан Jared Updike 26 August 2018 в 08:24
поделиться

Мне нужен был неизменный метод перемещения (тот, который не менял исходный массив), поэтому я применил принятый ответ @ Reid, чтобы просто использовать Object.assign для создания копии массива перед выполнением сращивания.

Array.prototype.immutableMove = function (old_index, new_index) {
  var copy = Object.assign([], this);
  if (new_index >= copy.length) {
      var k = new_index - copy.length;
      while ((k--) + 1) {
          copy.push(undefined);
      }
  }
  copy.splice(new_index, 0, copy.splice(old_index, 1)[0]);
  return copy;
};

Вот jsfiddle, показывающий его в действии .

5
ответ дан Javid Jamae 26 August 2018 в 08:24
поделиться

Array.move.js

Summary

Перемещает элементы внутри массива, возвращая массив, содержащий перемещенные элементы.

Синтаксис

array.move(index, howMany, toIndex);

Параметры

index: Индекс, по которому нужно перемещать элементы. Если отрицательный, индекс начнется с конца.

howMany: количество элементов, которые нужно переместить из индекса.

toIndex: указатель массива, в который нужно поместить перемещенные элементы. Если отрицательный, toIndex начнется с конца.

Использование

array = ["a", "b", "c", "d", "e", "f", "g"];

array.move(3, 2, 1); // returns ["d","e"]

array; // returns ["a", "d", "e", "b", "c", "f", "g"]

Polyfill

Array.prototype.move || Object.defineProperty(Array.prototype, "move", {
    value: function (index, howMany, toIndex) {
        var
        array = this,
        index = parseInt(index) || 0,
        index = index < 0 ? array.length + index : index,
        toIndex = parseInt(toIndex) || 0,
        toIndex = toIndex < 0 ? array.length + toIndex : toIndex,
        toIndex = toIndex <= index ? toIndex : toIndex <= index + howMany ? index : toIndex - howMany,
        moved;

        array.splice.apply(array, [toIndex, 0].concat(moved = array.splice(index, howMany)));

        return moved;
    }
});
2
ответ дан Jonathan Neal 26 August 2018 в 08:24
поделиться

Метод splice из Array может помочь: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice

Просто имейте в виду, что это может быть относительно дорого, поскольку оно должно активно переиндексировать массив.

6
ответ дан Ken Franqueiro 26 August 2018 в 08:24
поделиться

My 2c. Легко читается, он работает, он работает быстро, он не создает новые массивы.

function move(array, from, to) {
  if( to === from ) return array;

  var target = array[from];                         
  var increment = to < from ? -1 : 1;

  for(var k = from; k != to; k += increment){
    array[k] = array[k + increment];
  }
  array[to] = target;
  return array;
}
19
ответ дан Merc 26 August 2018 в 08:24
поделиться

Вы можете реализовать базовое исчисление и создать универсальную функцию для перемещения элемента массива из одной позиции в другую.

Для JavaScript это выглядит так:

function magicFunction (targetArray, indexFrom, indexTo) { 

    targetElement = targetArray[indexFrom]; 
    magicIncrement = (indexTo - indexFrom) / Math.abs (indexTo - indexFrom); 

    for (Element = indexFrom; Element != indexTo; Element += magicIncrement){ 
        targetArray[Element] = targetArray[Element + magicIncrement]; 
    } 

    targetArray[indexTo] = targetElement; 

}

Check

http://www.gloommatter.com/DDesign/programming/moving-any-array-elements-universal-функция. HTML

6
ответ дан S. Albano 26 August 2018 в 08:24
поделиться

Вот мое единственное решение ES6 Liner с необязательным параметром on.

if (typeof Array.prototype.move === "undefined") {
  Array.prototype.move = function(from, to, on = 1) {
    this.splice(to, 0, ...this.splice(from, on))
  }
}

Адаптация первого решения, предложенного digiguru

Параметр on - это номер элемента, начиная с from, который вы хотите переместить.

4
ответ дан Serban Petrescu 26 August 2018 в 08:24
поделиться

Мне нравится этот путь. Он работает, он быстрый и элегантный.

function arraymove(arr, fromIndex, toIndex) {
    var element = arr[fromIndex];
    arr.splice(fromIndex, 1);
    arr.splice(toIndex, 0, element);
}

Примечание: всегда помните, чтобы проверить границы массива.

111
ответ дан SteakOverflow 26 August 2018 в 08:24
поделиться

Метод splice () добавляет / удаляет элементы в / из массива и возвращает удаленные элементы.

Примечание. Этот метод изменяет исходный массив. / w3schools /

Array.prototype.move = function(from,to){
  this.splice(to,0,this.splice(from,1)[0]);
  return this;
};

var arr = [ 'a', 'b', 'c', 'd', 'e'];
arr.move(3,1);//["a", "d", "b", "c", "e"]


var arr = [ 'a', 'b', 'c', 'd', 'e'];
arr.move(0,2);//["b", "c", "a", "d", "e"]

, поскольку функция chainable тоже работает:

alert(arr.move(0,2).join(','));

demo here

27
ответ дан user 26 August 2018 в 08:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: