js-xlsx - get particular rows of excel sheet - javascript

I have an Excel sheet which has 500 rows. I am trying to get the rows from 101 to 200.
I have searched in google, and I have found an example to get starting rows, e.g. 1 to 100 or 1 to 1000, or even 1 to any number.
But I haven't found any code to get rows from mth row to nth row (Here 'm' and 'n' can be any number eg m=101 to n=200)
Below is the code which I have found to get first 100 rows:
let workbook = XLSX.readFile('./files/uploaded_files/testfile.xlsx', {sheetRows: 100})
const wsname = workbook.SheetNames[0];
const ws = workbook.Sheets[wsname];
var exceldata = XLSX.utils.sheet_to_json(ws);
Even if there is any other module to get the rows in between, I would like to know if there is any ?

Using a smaller example of:
There are several options:
You can use your current approach and slice the array returned from sheet_to_json e.g.
// option 1
const maxRow = 6;
const minRow = 3;
const wb = XLSX.readFile("./Book1.xlsx", {sheetRows: maxRow});
const ws = wb.Sheets[wb.SheetNames[0]];
let data = XLSX.utils.sheet_to_json(ws);
data = data.slice(minRow <= 2 ? 0 : minRow - 2);
console.log(data);
It's minRow - 2 to account for 1 row being headers and that the other 1 is to include row 3, not exclude it. This produces:
[
{ a: 4, b: 5, c: 6 },
{ a: 7, b: 8, c: 9 },
{ a: 10, b: 11, c: 12 },
{ a: 13, b: 14, c: 15 }
]
Another option is to combine use of the range and header (see here) options. range allows you to control what range is considered by sheet_to_json and header is used to define the keys used in the output array of objects.
You can use this after importing the whole file or continue to use the sheetRows option as well e.g.:
// option 2
const importRange = "A3:F6";
const headers = ["a", "b", "c"];
const wb = XLSX.readFile("./Book1.xlsx"); // not using sheetRows
const ws = wb.Sheets[wb.SheetNames[0]];
const data = XLSX.utils.sheet_to_json(ws, {range: importRange, header: headers});
console.log(data);
Which produces:
[
{ a: 4, b: 5, c: 6 },
{ a: 7, b: 8, c: 9 },
{ a: 10, b: 11, c: 12 },
{ a: 13, b: 14, c: 15 }
]
Noting that if you omit the headers option then the output is:
[
{ '4': 7, '5': 8, '6': 9 },
{ '4': 10, '5': 11, '6': 12 },
{ '4': 13, '5': 14, '6': 15 }
]
Because the values in row 3 become the new default headers (which I think you probably don't want).
Finally, if you don't know the headers in advance you can just get an array of arrays and figure the headers out later:
// option 3
const importRange = "A3:F6";
const headers = 1;
const wb = XLSX.readFile("./Book1.xlsx"); // not using sheetRows
const ws = wb.Sheets[wb.SheetNames[0]];
const data = XLSX.utils.sheet_to_json(ws, {range: importRange, header: headers});
console.log(data);
Which produces:
[
[ 4, 5, 6 ],
[ 7, 8, 9 ],
[ 10, 11, 12 ],
[ 13, 14, 15 ]
]

Related

Find minimum in array of dictionaries? [duplicate]

This question already has answers here:
Finding the max value of an attribute in an array of objects
(21 answers)
Compare JavaScript Array of Objects to Get Min / Max
(17 answers)
Closed 2 months ago.
I have something like :
var array = [
{'a':3,'b':4},
{'a':1,'b':8},
{'a':9,'b':7}]
What is an elegant one line to find the min/max of the key 'a' (max=9, min = 1) ?
I know it is simple but i couldn't find a one line solution only loops.
Logic
Create a simple array of the required nodes.
Use Math.max with the spread syntax to get the maximum.
const array = [{ a: 3, b: 4 },{ a: 1, b: 8 },{ a: 9, b: 7 }];
const max = Math.max(...array.map(({ a }) => a));
console.log(max);
Apply the same logic for min as well and use Math.min
const array = [{ a: 3, b: 4 },{ a: 1, b: 8 },{ a: 9, b: 7 }];
const nodes = array.map(({ a }) => a);
const maxMin = { max: Math.max(...nodes), min: Math.min(...nodes)};
console.log(maxMin);
you can do something like this
var array = [
{ a: 3, b: 4 },
{ a: 1, b: 8 },
{ a: 9, b: 7 },
];
const arrayA = array.map((v) => v.a);
const maxA = Math.max(...arrayA);
const minA = Math.min(...arrayA);
console.log({ minA, maxA });
Tried to keep it in 1 line.
var array = [
{ a: 3, b: 4 },
{ a: 1, b: 8 },
{ a: 9, b: 7 },
];
const result = {
min: Math.min(...array.map((x) => x.a)),
max: Math.max(...array.map((x) => x.a)),
};
console.log(result);

Generate new order of numbers from array

I'm currently trying to generate a new order of numbers from a current array with numbers from 1 - 10.
For example, I have arrary like this:
data = [
{
0: 1,
1: 2,
2: 3,
3: 4,
4: 5,
5: 6
},
{
0: 1,
1: 2,
2: 3,
3: 4,
4: 5,
5: 8
}
]
And i'm trying to generate a new order from this array from numbers from 1 - 10.
For example:
I want it to generate a new order like this:
0: 1,
1: 2,
2: 3,
3: 4,
4: 5,
5: 7 (The new number)
Where it checks the order of the array, and make a new order with numbers from 1 - 10
First thing to do is to create an object with the total values. We can accomplish this by looping over each object in the array and add each value to a new object. For this we can use the reduce method on the data array.
After that loop over the object with the totals and divide each value with the amount of objects that are present in the data array.
Use Math.round() to round each value to the nearest whole number.
const data = [{
0: 1,
1: 2,
2: 3,
3: 4,
4: 5,
5: 6
},
{
0: 1,
1: 2,
2: 3,
3: 4,
4: 5,
5: 8
}
];
function getDataTotal(data) {
const totalObject = data.reduce((total, curObj) => {
for (const key of Object.keys(curObj)) {
total[key] = total[key]
? total[key] + curObj[key]
: curObj[key];
}
return total;
}, {});
const averageObject = {};
for (const [key, value] of Object.entries(totalObject)) {
averageObject[key] = Math.round(value / data.length);
}
return averageObject;
}
const averageObject = getDataTotal(data);
console.log(averageObject);
Make sure you have the same keys on both objects.
const data = [
{0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6},
{0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 8},
]
getAverageValueOfMappingElements() {
const keys = Object.keys(data[0])
return [...keys].map(key => {
return (data[0][key] + data[1][key]) / 2
})
}

javascript, convert an array of objects to an array of arrays vertically

I have a CSV file that I have successfully read in with d3.csv. The result is a JSON file where each line consists of an array element and each array element is an object with key/value pairs matching the column headers.
I need this in a "vertical" format, as an array of arrays, where each inner array consists of the value for each object.
Here is an example to run in Node:
> a = new Array();
[]
> a.push({"b":2, "c": 4, "d":6, "e": 8});
1
> a.push({"b":3, "c": 6, "d":9, "e": 12});
2
> a.push({"b":4, "c": 8, "d":12, "e": 16});
3
> a.push({"b":5, "c": 10, "d":15, "e": 20});
4
> a
[
{ b: 2, c: 4, d: 6, e: 8 },
{ b: 3, c: 6, d: 9, e: 12 },
{ b: 4, c: 8, d: 12, e: 16 },
{ b: 5, c: 10, d: 15, e: 20 }
]
> x = [[2,3,4,5],[4,6,8,10],[6,9,12,15],[8,12,16,20]]
[ [ 2, 3, 4, 5 ], [ 4, 6, 8, 10 ], [ 6, 9, 12, 15 ], [ 8, 12, 16, 20 ] ]
> x
[
[ 2, 3, 4, 5 ],
[ 4, 6, 8, 10 ],
[ 6, 9, 12, 15 ],
[ 8, 12, 16, 20 ]
]
>
Here, [a] represents the array of object I have while [x] represents the array of arrays I would like to have.
My data file is very wide and has many columns. I have tried several toy solutions, and I can iterate through the array, select each element, then iterate through each element and select each key, grab the value, and push it to a new array. However, this is nasty and very easy to break. Surely there is a better way.
If I had a list of lists, I could flip the rows and columns. Unfortunately, I have a list of object, read in with D3.csv().
My primary language was (note, was) Perl, and a Perl-ish solution is natural to me. My current application runs client side in a browser, and I need a client side solution in JavaScript.
You can achieve this in a number of ways, but since it appears that all objects in your source array have the same properties, the most direct may be a nested map() call. The outer map() is called on the Object.keys() of the first element of the array, and the inner map() uses each iterated key on every object in the source array.
const a = [{ b: 2, c: 4, d: 6, e: 8 }, { b: 3, c: 6, d: 9, e: 12 }, { b: 4, c: 8, d: 12, e: 16 }, { b: 5, c: 10, d: 15, e: 20 }];
const result = Object.keys(a[0]).map(key => a.map(o => o[key]));
console.log(result);
If the objects had varying properties, you could use a reduce() call to accumulate all the values of like properties.
const a = [{ b: 2, c: 4, d: 6, e: 8 }, { b: 3, c: 6, d: 9, e: 12 }, { b: 4, c: 8, d: 12, e: 16 }, { b: 5, c: 10, d: 15, e: 20 }];
const result = Object.values(
a.reduce((acc, obj) => {
Object.keys(obj).forEach(key =>
(acc[key] ??= []).push(obj[key]));
return acc;
}, {}));
console.log(result);
I like #pilchard's d3 agnostic answer; but if you're interested in a d3 driven answer you can use d3.transpose on an array of arrays with a pre-processing step of removing the keys of the objects with Object.values:
const a = [
{ b: 2, c: 4, d: 6, e: 8 },
{ b: 3, c: 6, d: 9, e: 12 },
{ b: 4, c: 8, d: 12, e: 16 },
{ b: 5, c: 10, d: 15, e: 20 }
]
const x = d3.transpose(a.map(o => Object.values(o)));
console.log(x);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.5.0/d3.min.js"></script>

How to get a new array containing some random elements from an old array in Javascript

I am making a quiz app in react native, it has this array of objects in which each object contains a question statement,choices and the correct choice. There will be total 15 objects in this, but i require a new array that contains only 5 of the objects of this array. They should be selected at random everytime i start the quiz.
How to get that array, help
const questions = [
new quizQuestions(
'What is capital of Pakistan?',
['Karachi', 'Islamabad', 'Lahore', 'Peshawar'],
'Islamabad',
),
new quizQuestions(
'What is capital of India?',
['delhi', 'Islamabad', 'zcjzj', 'Peshawar'],
'delhi',
),
new quizQuestions(
'What is capital of Pakistan?',
['Karachi', 'Islamabad', 'Lahore', 'Peshawar'],
'Islamabad',
),
]
use JS random method to generate random numbers from 0 to 15
//your whole set of questions array
const questions = [
new quizQuestions(
'What is capital of Pakistan?',
['Karachi', 'Islamabad', 'Lahore', 'Peshawar'],
'Islamabad',
),
new quizQuestions(
'What is capital of India?',
['delhi', 'Islamabad', 'zcjzj', 'Peshawar'],
'delhi',
),
new quizQuestions(
'What is capital of Pakistan?',
['Karachi', 'Islamabad', 'Lahore', 'Peshawar'],
'Islamabad',
),
];
//random 5 question array
const selectedQuestionArr = [];
let addedIndex = [];
for (var i = 0; i < 5; i++) {
let randomIdx;
do {
randomIdx = Math.floor(Math.random() * 15);
}
while(addedIndex.indexOf(randomIdx) > -1);
//record added index to not include it in the next cycle
addedIndex.push(randomIdx);
//push the randomly selected question
selectedQuestionArr.push(questions[randomIdx]);
}
console.log(selectedQuestionArr);
Very much random what you need.
Using generator function:
const questions = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
function* randomise(arr, numOfElem) {
// Create a copy of question so that wont effect actual array
let copyArray = [...arr];
// Use copyArray to generate random as closure, so that it never go out of index
const getRandom = () => Math.floor(Math.random() * copyArray.length);
// This is generator function run always
while (true) {
// If numOfElem is greater, then clone again
// suppose you have 15 question but you take 6. SO after 2 iteration, copyArray will have only 3 element so clone again
if (numOfElem > copyArray.length) {
// Clone again
copyArray = [...arr];
}
// pick 5 random data.
let result = [];
for (let i = 0; i < numOfElem; i++) {
result.push(copyArray.splice(getRandom(), 1)[0]);
}
yield result;
}
}
const questionGenerator = randomise(questions, 5);
console.log(questionGenerator.next().value); // random [ 11, 3, 7, 2, 8 ]
console.log(questionGenerator.next().value); // random [ 12, 13, 14, 9, 5 ]
console.log(questionGenerator.next().value); // random [ 6, 1, 4, 15, 10 ]
console.log(questionGenerator.next().value); // random [ 14, 12, 8, 2, 13 ]
console.log(questionGenerator.next().value); // random [ 9, 3, 10, 6, 11 ]
Same but without generator function.
const questions = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
const randomise = (arr, numOfElem) => {
let copyArray = [...arr];
const getRandom = () => Math.floor(Math.random() * copyArray.length);
return () => {
// If numOfElem is greater, then clone again
// suppose you have 15 question but you take 6. SO after 2 iteration, copyArray will have only 3 element so clone again
if (numOfElem > copyArray.length) {
// Clone again
copyArray = [...arr];
}
// pick 5 random data.
let result = [];
for (let i = 0; i < numOfElem; i++) {
result.push(copyArray.splice(getRandom(), 1)[0]);
}
return result;
};
};
const questionGenerator = randomise(questions, 5);
console.log(questionGenerator()); // random [ 11, 3, 7, 2, 8 ]
console.log(questionGenerator()); // random [ 12, 13, 14, 9, 5 ]
console.log(questionGenerator()); // random [ 6, 1, 4, 15, 10 ]
console.log(questionGenerator()); // random [ 14, 12, 8, 2, 13 ]
console.log(questionGenerator()); // random [ 9, 3, 10, 6, 11 ]
For your particular case, i couldn't find any lodash function for this i have implemented my own javascript logic for this you can have a look.
https://codesandbox.io/s/shuffled-array-ltzud
Almost a repeat of Azad's answer :D but I found our method to be very simple and straight forward.
pass in selectedQuestions as an empty array
function randomizeQuestions(allQuestions,selectedQuestions,numberToSelect)
{
selectedIndex = [];
var randIndex;
for(var i = 0; i < numberToSelect; i++)
{
do{
randIndex = Math.floor(Math.random() * allQuestions.length);
}while(selectedIndex.includes(randIndex));
selectedIndex.push(randIndex);
selectedQuestions.push(allQuestions[randIndex]);
}
}

Merge two objects with different keys in chartjs bar

I have two jsons:
first: {
"a": 1,
"b": 9,
"c": 12,
"d": 5
}
and
second: {
"a": 7,
"e": 8,
"b": 11,
"f": 7
}
and i want to create chartjs bar that include both json (with two datasets).
The labels should be 'a', 'b', 'c', 'd', 'e', 'f' and the "first" dataset's data will be: 1, 9, 12, 5, 0, 0. The "second" dataset's data will be: 7, 11, 0, 0, 8, 7.
My code right now:
var barChartData = {
labels: Object.keys(first),
datasets:[
{
label:'first',
data: Object.values(first)
},
{
label: 'second',
data: Object.values(second)
}]
};
window.myBar = new Chart(document.getElementById("barChart").getContext("2d"),
{
type:'bar',
data: barChartData
});
The problem is that i want the labels to be from the keys of both 'first' and 'second' jsons and not just from the 'first' and also that the values will be suitable to the keys.
Is there any simple way to do this?
It looks like you want both objects to have the same keys but with a value of zero when the keys aren't defined. There are several ways to do this. One option would be to make a list of the combined keys of both objects and just loop over them setting the object's value to 0 if the key doesn't exist:
let first = {"a": 1,"b": 9,"c": 12,"d": 5 }
let second = {"a": 7,"e": 8,"b": 11,"f": 7}
Object.keys(Object.assign({}, first, second)) // get combined keys
.forEach(k => {
if (!first.hasOwnProperty(k)) first[k] = 0; // set 0 if key is not in object
if (!second.hasOwnProperty(k)) second[k] = 0;
})
console.log(first, second)

Categories

Resources