在数组对象的 middle/first 中插入后更改数组对象的键
Change keys of array object after inserting in the middle/first of array object
我正在开发类似 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"}
];
columns
数组中对象的 binding
属性 将用于获取每一行的列值。
但是,我在某些字母键的中间插入新列时遇到了问题。
假设我需要在列 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
。
我想我必须在每一行的所有字母键之间插入一个新的 cell/item,并重命名所有键(在这种情况下,将键 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 行时。
我有两个问题:
- 最有效的方法是什么?
- 如果我有很多行和列,重命名这些键时会出现性能问题吗?
不要对行或列使用文字名称。
为了提高性能,link 一个数据对象直接到列 and/or 行(在元胞数组中制作一些属性,如 _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);
所以...您可以毫无困难地 insert/delete/sort/rename 行。
您可以毫无困难地insert/delete/sort/rename 列中的所有单元格。
如果顺序很重要,您可以“映射”按 row/col
排序的单元格
首先,我认为 Andam 对问题的评论是正确的。肯定有更好的方法从 object 数组中制作 spreadsheet-like 显示。我的想法是简单地维护一个 header object 数组,其中包含(至少)列标题和要在列中显示的 属性 的名称。然后插入一列将只涉及更新该数组(并且可能默认为您的行设置 属性 值。)
但您仍想按照您的问题建议的方式进行,这里有一个可能的实现方式:
// 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
只是将 (zero-based) 索引转换为 spreadsheet-like 列标识符 ('A'
, 'B'
, 'C'
, ... 'Z'
, 'AA'
, 'AB'
, ... 'AZ'
, 'BA'
, 'BB'
, ... 'BZ'
, ... 'ZZ'
, 'AAA'
, ...)
它使用alphaNum
,它做heavy-lifting,基于一个字符数组来表示pseudo-digits用过。
insertColumn
是主要功能。它采用插入列的 (zero-based) 索引、数据和用于创建单元格值的函数。它通过提取值来更改每一行,插入由您的函数创建的新值,然后从新索引映射回列名,然后用 Object .fromEntries
.[=28= 重建 object ]
这里我们向它传递一个虚拟 column-creation 函数,我们可以注意到,它传递了行 object、行索引和新列索引。
我不知道它将如何处理您的实际数据,但您描述的数字不会让我太担心。您可以在此处进行一些小的优化。例如,我们不需要重新计算每一行的列名,而是可以缓存它们。但如果性能达不到你的期望,我只会打扰他们。
而且,我再次认为有更好的方法可以解决可能存在的潜在问题。
我正在开发类似 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"}
];
columns
数组中对象的 binding
属性 将用于获取每一行的列值。
但是,我在某些字母键的中间插入新列时遇到了问题。
假设我需要在列 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
。
我想我必须在每一行的所有字母键之间插入一个新的 cell/item,并重命名所有键(在这种情况下,将键 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 行时。
我有两个问题:
- 最有效的方法是什么?
- 如果我有很多行和列,重命名这些键时会出现性能问题吗?
不要对行或列使用文字名称。
为了提高性能,link 一个数据对象直接到列 and/or 行(在元胞数组中制作一些属性,如 _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);
所以...您可以毫无困难地 insert/delete/sort/rename 行。
您可以毫无困难地insert/delete/sort/rename 列中的所有单元格。
如果顺序很重要,您可以“映射”按 row/col
排序的单元格首先,我认为 Andam 对问题的评论是正确的。肯定有更好的方法从 object 数组中制作 spreadsheet-like 显示。我的想法是简单地维护一个 header object 数组,其中包含(至少)列标题和要在列中显示的 属性 的名称。然后插入一列将只涉及更新该数组(并且可能默认为您的行设置 属性 值。)
但您仍想按照您的问题建议的方式进行,这里有一个可能的实现方式:
// 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
只是将 (zero-based) 索引转换为 spreadsheet-like 列标识符 ('A'
,'B'
,'C'
, ...'Z'
,'AA'
,'AB'
, ...'AZ'
,'BA'
,'BB'
, ...'BZ'
, ...'ZZ'
,'AAA'
, ...)它使用
alphaNum
,它做heavy-lifting,基于一个字符数组来表示pseudo-digits用过。insertColumn
是主要功能。它采用插入列的 (zero-based) 索引、数据和用于创建单元格值的函数。它通过提取值来更改每一行,插入由您的函数创建的新值,然后从新索引映射回列名,然后用Object .fromEntries
.[=28= 重建 object ]
这里我们向它传递一个虚拟 column-creation 函数,我们可以注意到,它传递了行 object、行索引和新列索引。
我不知道它将如何处理您的实际数据,但您描述的数字不会让我太担心。您可以在此处进行一些小的优化。例如,我们不需要重新计算每一行的列名,而是可以缓存它们。但如果性能达不到你的期望,我只会打扰他们。
而且,我再次认为有更好的方法可以解决可能存在的潜在问题。