lodash - удаляет столбцы из таблицы данных (2D матрица), если все значения равны нулю - PullRequest
0 голосов
/ 08 февраля 2019

У меня есть 2D-матрица, подобная этой, где первая строка - это имена столбцов, а другие строки - значения.

var datatable = [
  ["a", "b",   "c",   "d"],  //first row are columns names
  [ 1,   0,     null,  3 ],  //other rows are values
  [ 6,   null,  null,  8 ]
];

Я хочу удалить столбцы, когда все значения равны null, как ожидалосьрезультат ниже:

var datatable = [
  ["a", "b",   "d"],  //first row are columns names
  [ 1,   0,     3 ],  //other rows are values
  [ 6,   null,  8 ]
];

Количество строк и столбцов может варьироваться.Если есть компактный и быстрый способ добиться этого с помощью lodash, это прекрасно.

Ответы [ 4 ]

0 голосов
/ 08 февраля 2019

Вот мой подход, использующий map(), filter() и some().

var datatable = [
  ["a", "b",   "c",   "d"],
  [ 1,   0,     null,  3 ],
  [ 6,   null,  null,  8 ]
];

let res = datatable.map(
  x => x.filter((_, idx) => datatable.slice(1).some(arr => arr[idx] !== null))
);

console.log(res);
0 голосов
/ 08 февраля 2019

Немного более длинный код, но похожая идея.

var datatable = [
  ["a", "b", "c", "d"],
  [1, 0, null, 3],
  [6, null, null, 8]
];

/* first create a simple key val map as {a:[1,6],b:[0,null] etc to weed out the keys with all nulls */

let keyValMap = datatable.reduce((acc,arr,index) => {
 if(index===0) {
  arr.forEach(key => {
   if(!acc[key])
    acc[key]=[]
  });
 } else {
  Object.keys(acc).map((key,index) => acc[key].push(arr[index])); 
 }
 return acc;
},{});

// now extract only those keys that do not have every element as null
let validKeys = Object.keys(keyValMap).filter(key => !keyValMap[key].every(i => i===null));

// pivot back from keyValMap the values based on validKeys
let updatedDataTable = [validKeys,  ...validKeys.map(key =>  keyValMap[key]).reduce((acc,val)=>{
  val.forEach((elem,i) => {
    if(!acc[i]) acc[i]=[];
    acc[i].push(elem)
  });
  return acc;
 },[]) ]

console.log(updatedDataTable);
0 голосов
/ 08 февраля 2019

Используйте .flow(), который создает функцию, которая транспонирует массив с помощью _.unzip(), отклоняет массивы со всеми значениями null, а затем распаковывает массив обратно в исходную форму:

const { flow, partialRight: pr, unzip, reject, tail, every, isNull } = _; // convert to imports

const fn = flow(
  unzip,
  pr(reject, flow(tail, pr(every, isNull))),
  unzip,
);

const datatable = [
  ["a", "b",   "c",   "d"],  //first row are columns names
  [ 1,   0,     null,  3 ],  //other rows are values
  [ 6,   null,  null,  8 ]
];

const result = fn(datatable);

console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

И более быстрое решение lodash / fp:

const { flow, unzip, reject, tail, every, isNull } = _; // convert to imports

const fn = flow(
  unzip,
  reject(flow(
    tail,
    every(isNull)
  )),
  unzip,
);

const datatable = [
  ["a", "b",   "c",   "d"],  //first row are columns names
  [ 1,   0,     null,  3 ],  //other rows are values
  [ 6,   null,  null,  8 ]
];

const result = fn(datatable);

console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash@4(lodash.min.js+lodash.fp.min.js)'></script>
0 голосов
/ 08 февраля 2019

Сначала можно получить столбцы со всеми значениями null, а затем отфильтровать строки.

var datatable = [["a", "b", "c", "d"], [1, 0, null, 3], [6, null, null, 8]],
    cols = datatable
        .slice(1)                                                   // omit header
        .reduce((r, a) => a.map((v, i) => r[i] || v !== null), []);

datatable = datatable.map(a => a.filter((_, i) => cols[i]));

console.log(datatable);
.as-console-wrapper { max-height: 100% !important; top: 0; }
...