Измените ключи объекта массива после вставки в середине / первом объекте массива

Я работаю над приложением в стиле Excel, но у меня проблемы с многомерным массивом.

У меня есть массив столбцов, который выглядит так:

var columns = [
  {A: {binding: "A",header: "A"},
  {B: {binding: "B",header: "B"},
  {C: {binding: "C",header: "C"}
];

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

var data = [
   {A:"row 0 col A", B: "row 0 col B", C:"row 0 col C"},
   {A:"row 1 col A", B: "row 1 col B", C:"row 1 col C"},
   {A:"row 2 col A", B: "row 2 col B", C:"row 2 col C"}
];

Свойство binding объектов в массиве columns будет использоваться для получения значения столбца для каждой строки.

Однако я сталкиваюсь с проблемой при вставке нового столбца в середину некоторых буквенных клавиш. Скажем, мне нужен новый столбец между столбцом A и столбцом B. Результат выглядит так:

var columns = [
  {A: {binding: "A",header: "A"},
  {B: {binding: "B",header: "B"},
  {C: {binding: "C",header: "C"},
  {D: {binding: "D",header: "D"}
];

Он просто помещает новый столбец в columns.

Я думаю, мне нужно вставить новую ячейку / элемент между всеми алфавитными клавишами для каждой строки и переименовать все ключи (в этом случае переименовать ключи B в C, C в D и т. Д.).

Я бы хотел, чтобы результат выглядел так:

var data = [
   {A:"row 0 col A", B:"new col inserted here", C:"row 0 col B", D:"row 0 col C"},
   {A:"row 1 col A", B:"new col inserted here", C:"row 1 col B", D:"row 1 col C"},
   {A:"row 2 col A", B:"new col inserted here", C:"row 2 col B", D:"row 2 col C"}
];

Меня беспокоят проблемы с производительностью, если я переименую все эти ключи, особенно если у меня 120 столбцов (A-DZ) и 100 строк.

У меня два вопроса:

  • Как это сделать наиболее эффективно?
  • Будут ли у меня проблемы с производительностью при переименовании этих ключей, если у меня много строк и столбцов?

person hafizh    schedule 14.10.2020    source источник
comment
Как выбрать новое имя крайнего правого столбца при вставке? Здесь это «Д», но как определить его в произвольном случае?   -  person Scott Sauyet    schedule 14.10.2020
comment
Я бы не стал беспокоиться о производительности переименования ~ 12K ключей, если бы я не протестировал и не увидел, что это проблема. Я ожидал, что это будет быстро.   -  person Scott Sauyet    schedule 14.10.2020
comment
@ScottSauyet, я использую этот код stackoverflow.com/questions/12504042/, но мне нужно немного изменить его, чтобы я мог установить начальный символ. пример: я хочу, чтобы функция начиналась с приращения с char 'C'   -  person hafizh    schedule 14.10.2020
comment
Я знаю, что вы хотите, чтобы новый столбец был виден между A и B в пользовательском интерфейсе, но зачем он вам нужен между A и B? Вы используете последовательный индекс для доступа? например, индекс 0 означает A, а индекс 1 означает B и т. д.   -  person Andam    schedule 14.10.2020
comment
Я думаю, что у @Andam это прямо здесь. Объекты по своей сути являются неупорядоченными контейнерами. Если вы поддерживаете внешний массив имен свойств, представляющих столбцы, то вставка просто обновляет этот массив (и, возможно, добавляет значения по умолчанию для нового имени свойства в каждой строке).   -  person Scott Sauyet    schedule 14.10.2020


Ответы (2)


Во-первых, я считаю, что комментарий к вопросу от Андама правильный. Безусловно, есть лучшие способы сделать отображение массива объектов в виде электронной таблицы. Я думал просто поддерживать массив объектов заголовка, содержащий (как минимум) заголовок столбца и имя свойства, отображаемого в столбце. Затем вставка столбца просто потребует обновления этого массива (и, возможно, значения этого свойства по умолчанию для ваших строк).

Но вы все равно хотите действовать так, как предлагает ваш вопрос, вот возможная реализация:

// Utility function
const alphaNum = (cs) => (n) => 
  n < cs.length
    ? cs [n % cs.length]
    : alphaNum (cs) (Math.floor(n / cs.length) - 1) + cs [n % cs.length]

// Helper function
const toColumnName = alphaNum ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' .split (''))

// Main function
const insertColumn = (index, data, makeVal) => 
  data .map ((item, i, arr, vals = Object .values (item)) => Object.fromEntries ([
    ...vals .slice (0, index),
    makeVal (item, i, index),
    ...vals .slice (index)
  ] .map ((item, i) => [toColumnName(i), item])))

// Dummy cell creation function
const createCell = (row, rowNbr, colNbr) => 
  `new col inserted at row ${rowNbr} col ${colNbr}`

// Sample data
const data = [{A: 'row 0 col A', B: 'row 0 col B', C: 'row 0 col C'}, {A: 'row 1 col A', B: 'row 1 col B', C: 'row 1 col C'}, {A: 'row 2 col A', B: 'row 2 col B', C: 'row 2 col C'}]

// Demo
console .log (insertColumn (1, data, createCell))
.as-console-wrapper {max-height: 100% !important; top: 0}

  • toColumnName просто преобразует индекс (отсчитываемый от нуля) в идентификатор столбца, подобный электронной таблице ('A', 'B', 'C', ... 'Z', 'AA', 'AB', ... 'AZ', 'BA', 'BB',. .. 'BZ', ... 'ZZ', 'AAA', ...)

  • Он использует alphaNum, который выполняет тяжелую работу, основываясь на массиве символов для представления используемых псевдо-цифр.

  • insertColumn - основная функция. Он принимает (отсчитываемый от нуля) индекс вставленного столбца, данные и функцию, используемую для создания значения вашей ячейки. Он изменяет каждую строку, извлекая значения, вставляя новую, созданную вашей функцией, а затем сопоставляя имена столбцов с новыми индексами, а затем перестраивая объект с Object .fromEntries.

Здесь мы передаем фиктивную функцию создания столбца, которой, как мы можем заметить, передается объект строки, индекс строки и индекс нового столбца.

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

И, опять же, я думаю, что есть более эффективные способы решения вероятной основной проблемы.

person Scott Sauyet    schedule 14.10.2020
comment
Я согласен с вами, есть гораздо лучший способ решить эту проблему, например, @eduardo. но я не могу изменить структуру данных моего приложения, готового к публикации, таким образом. - person hafizh; 14.10.2020
comment
Понял. Вот почему я дал ответ, который, как мне кажется, может помочь. Но если у вас будет время на рефакторинг, это может быть лучшим подходом. - person Scott Sauyet; 14.10.2020

Не используйте буквальные имена для строк или столбцов.

Чтобы повысить производительность, свяжите один объект данных непосредственно со столбцом и / или строкой (сделайте некоторые атрибуты, такие как _row и _col в массиве ячеек) и поместите _cells в строки и столбцы.

Пример:

var data = {};

data.rows = [
{idx: 'A', _cells: []},
{idx: 'B', _cells: []},
{idx: 'C', _cells: []}
]

data.cols = [
{idx: 'A', _cells: []},
{idx: 'B', _cells: []},
{idx: 'C', _cells: []}
]

data.cells = [];

function addCell( rowIdx, colIdx, value) {
  var row = data.rows[rowIdx];
  var col = data.cols[rowIdx];
  var cell = {value: value, _row: row, _col: col};
  data.cells.push(cell);
  row._cells.push(cell);
  col._cells.push(cell);
}

for(var r=0; r<3; r++)
  for (var c=0;c<3; c++)
    addCell(r,c,'row ' + r + ' col ' + String.fromCharCode(65 + c));

console.log(data);

так что ... вы можете без труда вставлять / удалять / сортировать / переименовывать строки.

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

Если порядок важен, вы можете сопоставить ячейки, отсортированные по строке / столбцу

person Eduardo Jedliczka    schedule 14.10.2020
comment
Интересный подход, но меня беспокоят различные циркулярные ссылки. Есть ли веская причина, по которой ячейкам нужны ссылки на их строки и столбцы? - person Scott Sauyet; 14.10.2020
comment
ну, если вам нужно создать новую полную строку или столбец, в этом нет необходимости! Но если вы хотите создать ячейку раньше, сдвиг строки будет намного проще внутри столбцов. - person Eduardo Jedliczka; 15.10.2020