Create a new csv file with new columns
У меня есть локальный CSV-файл со списком сотрудников и их временя потраченое на работу в течение нескольких дней. Нужно считать текстовый файл и написать алгоритм на любом языке программирования,
который после отработки формирует новый CSV-файл со сводной таблицей по всем
сотрудники из исходного файла CSV.
Будет понятнее на примере
Input:
A, B, C
1a,1b,1c
2a,1b,2c
3a,1b,3c
1a,2b,4c
2a,2b,5c
3a,2b,6c
1a,3b,7c
2a,3b,8c
3a,3b,9c
a = EmployeeName,
b = Date,
c = WorkHours - this is my headers
Мне нужно получить новый файл с массивом:
Output:
A,1b,2b,3b
1a,1c,4c,7c
2a,2c,5c,8c
3a,3c,6c,9c
Это мой код, который читает файл и открывает его на странице.
<html>
<head>
<meta charset="utf-8" />
<title>Demo - CSV-to-Table</title>
</head>
You can use the CSVToArray() function mentioned in this blog entry.
<script type="text/javascript">
function Upload() {
var fileUpload = document.getElementById("fileUpload");
var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.csv|.txt)$/;
if (regex.test(fileUpload.value.toLowerCase())) {
if (typeof (FileReader) != "undefined") {
var reader = new FileReader();
reader.onload = function (e) {
var table = document.createElement("table");
var rows = e.target.result.split("\n");
for (var i = 0; i < rows.length; i++) {
var cells = rows[i].split(",");
if (cells.length > 1) {
var row = table.insertRow(-1);
for (var j = 0; j < cells.length; j++) {
var cell = row.insertCell(-1);
cell.innerHTML = cells[j];
}
}
}
var dvCSV = document.getElementById("dvCSV");
dvCSV.innerHTML = "";
dvCSV.appendChild(table);
}
reader.readAsText(fileUpload.files[0]);
} else {
alert("This browser does not support HTML5.");
}
} else {
alert("Please upload a valid CSV file.");
}
}
</script>
<input type="file" id="fileUpload" />
<input type="button" id="upload" value="Upload" onclick="Upload()" />
<hr />
<div id="dvCSV">
</div>
</html>
Помогите мне изменить его так, чтобы он принимал файл и создавал повторно обработанный файл со сведённой таблицей. Может ли кто-нибудь пролить свет на то, как лучше всего это сделать?
Can use Javascript, JQuerry, libraries Node.js(paraparse,read.csv,csvtojson,csv-parser e.t.c.)?
Ответы (1 шт):
На чистом JS.
Сортировку 1b,2b,3b не включал. Если она необходима. Сперва надо собрать все b, отсортировать и только после этого пройтись по таблице.
const CSV = `
A, B, C
1a,1b,1c
2a,1b,2c
3a,1b,3c
1a,2b,4c
2a,2b,5c
3a,2b,6c
1a,3b,7c
2a,3b,8c
3a,3b,9c
`
const table = CSV.trim().split(/\n/g).map((row) => row.split(/[\s,]+/g))
// Отделяем типы столбцов
const columns = table.splice(0, 1)[0]
// Определяем столбцы
const columnName = columns.findIndex((v) => /a/i.test(v))
const columnDate = columns.findIndex((v) => /b/i.test(v))
const columnWork = columns.findIndex((v) => /c/i.test(v))
// Раз нужно свернуть сотрудников, можно сразу собрать их в кучу
// ... заодно запомнить все варианты number:b
const A = []
const employees = table.reduce((a, v) => {
const name = v[columnName]
const date = v[columnDate]
const work = v[columnWork]
// Индекс столбца даты
let i = A.indexOf(date)
if (i === -1) {
i = A.push(date) - 1
}
if (!a[name]) {
a[name] = []
}
// Именно в этот индекс и вставляем, чтоб не промахнуться :)
a[name][i] = work
return a
}, {})
// Теперь просто сворачиваем каждую строку -> Сотрудник:Время
const result = [...Object.entries(employees)].map(([e, w]) => [e, w].flat().join(','))
// Добавляем первую строку даты
result.unshift(['A', ...A].join(','))
// Склеиваем строки
const newCSV = result.join(`\n`)
console.log(newCSV)
Разумеется:
- если столбцы именуются как-то подругому, необходимо изменить
columns.findIndex((v) => /EmployeeName/i.test(v))
- если дата пишется в каком либо формате, придется привести ее к реальной дате
new Date()и сравнивать метку времени - если имена сотрудников пишуться как "Ваня Иванов", создать регулярку
new RegExp("Ваня Иванов".replace(/\s+/g, ' '), 'i')
const CSV = `
Name, Date, Work
Jerrod Tate, Jun 29 2020, 5.2
Bianca Wright, Jun 29 2020, 5.4
Wayne Payne, Jun 29 2020, 6.5
Jerrod Tate, Jun 30 2020, 5
Heath Mcdaniel, Jun 30 2020, 6
Ezekiel Harrington, Jun 30 2020, 6.4
`
// Полноценная таблица
const table = CSV.trim().split(/[\n\r]+/g).map((row) => row.trim().split(/,+/g))
// Отделяем типы столбцов
const columns = table.shift()
// Определяем столбцы
const columnName = columns.findIndex((v) => /Name/i.test(v))
const columnDate = columns.findIndex((v) => /Date/i.test(v))
const columnWork = columns.findIndex((v) => /Work/i.test(v))
// Сортируем дату
const A = table.reduce((a, v) => {
const date = (new Date(v[columnDate])).valueOf()
a.includes(date) || a.push(date)
return a
}, []).sort()
const employees = table.reduce((a, v) => {
const name = v[columnName].trim().replace(/\s+/g, ' ')
const date = (new Date(v[columnDate])).valueOf()
const work = v[columnWork].trim()
let nw = [...a.entries()].find(([re]) => re.test(name))
if (!nw) {
// Здесь можно чем-то заполнить если не работали
nw = [null, { name, work: (new Array(A.length)).fill('0') }]
a.set(new RegExp(name, 'i'), nw[1])
}
nw[1].work[A.indexOf(date)] = work
return a
}, new Map())
// Далее делаем что угодно
const result = [...employees.entries()].map(([_, { name, work }]) => [name, ...work])
// Наши заголовки с датой
result.unshift(['Employee', ...A.map((d) => (new Date(d).toDateString()))])
result.map((v)=>console.log(v.join(', ')))