Cannot read property "length" of undefined? - javascript

I'm trying to make something for a little community I'm in. But I'm not very well versed in JavaScript and NodeJS yet. The script I'm making, is supposed to first find all possible combinations of a list of users in groups of 6.
Then I need to take each of those groups skill rating average, and compare so that I can find the two that matches the closest. This way we get two teams that can play against each other, and be somewhat balanced at least.
But my first issue is that I seem to be unable to even print out anything from the array that I'm making, and I don't understand why.
var filePath = 'data.txt';
function readFile() {
var data = [];
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream(filePath)
});
lineReader.on('line', function(line) {
var splitString = line.split(',');
var arr = {
sr: splitString[0],
role: splitString[1],
discord: splitString[3]
};
data.push(arr);
console.log(arr);
});
lineReader.on('close', () => {
return data;
});
}
function balance() {
var data = readFile();
for(var i = 0; i < data.length; i++) {
console.log(data[i]);
}
}
balance();
The output is always undefined. What am I doing wrong?

What you can do is not to change the nature of the reading function, instead change your approach.
I will give you two options.
Using callback:
var filePath = 'data.txt';
function readFile(callback) {
var data = [];
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream(filePath)
});
lineReader.on('line', function (line) {
var splitString = line.split(',');
var arr = {
sr: splitString[0],
role: splitString[1],
discord: splitString[3]
};
data.push(arr);
console.log(arr);
});
lineReader.on('close', () => {
callback(data);
});
}
function balance() {
readFile(function (data) {
for (var i = 0; i < data.length; i++) {
console.log(data[i]);
}
});
}
balance();
Using Promise:
var filePath = 'data.txt';
function readFile() {
return new Promise(function (resolve, reject) {
var data = [];
var lineReader = require('readline').createInterface({
input: require('fs').createReadStream(filePath)
});
lineReader.on('line', function (line) {
var splitString = line.split(',');
var arr = {
sr: splitString[0],
role: splitString[1],
discord: splitString[3]
};
data.push(arr);
console.log(arr);
});
lineReader.on('close', () => {
resolve(data);
});
});
}
function balance() {
readFile().then(function (data) {
for (var i = 0; i < data.length; i++) {
console.log(data[i]);
}
}, function (error) {
});
}
balance();

Using async await
const filePath = './data.txt';
async function readFile() {
return new Promise((resolve) => {
const data = [];
const lineReader = require('readline').createInterface({
input: require('fs').createReadStream(filePath),
});
lineReader.on('line', (line) => {
const [sr, role, discord] = line.split(',');
const arr = {
sr,
role,
discord,
};
data.push(arr);
});
lineReader.on('close', () => {
resolve(data);
});
});
}
async function balance() {
const data = await readFile();
for (let i = 0; i < data.length; i += 1) {
console.log(data[i]);
}
return 1;
}
balance().then(() => { });
Using observer pattern
const { EventEmitter } = require('events');
const fs = require('fs');
class FileParser extends EventEmitter {
constructor(file) {
super();
this.file = file;
}
parse() {
const self = this;
const data = [];
const lineReader = require('readline').createInterface({
input: require('fs').createReadStream(self.file),
});
lineReader.on('line', (line) => {
const [sr, role, discord] = line.split(',');
const arr = {
sr,
role,
discord,
};
data.push(arr);
});
lineReader.on('close', () => {
self.emit('done', data);
});
return this;
}
}
const fileParser = new FileParser('./data.txt');
fileParser
.parse()
.on('done', (data) => {
for (let i = 0; i < data.length; i += 1) {
console.log(data[i]);
}
});
Refactored a bit to use the latest ES6 syntax;

Related

Empty array is returned outside mongoose function

I'm trying to take some random values from Mongo using mongoose and push it to an array.
But the array is empty outside the function:
exports.Run = (req, res) => {
var response = {}
var you = "you"
response[you] = [];
Model.estimatedDocumentCount().exec(function (err, count) {
for (let i = 0; i < 8; i++) {
let random = Math.floor(Math.random() * count)
Model.findOne()
.skip(random)
.exec( function (err, result) {
response[you].push(result);
console.log(response); // Array is increased each iteration
})
}
})
console.log(response); // Array is empty here
res.status(200).send(response);
};
Please, how to fix that?
Thanks in advance.
Check this way. Hope it should work
exports.Run =async (req, res) => {
var response = {}
var you = "you"
response[you] = [];
var result = await Model.estimatedDocumentCount().exec(function (err, count) {
for (let i = 0; i < 8; i++) {
let random = Math.floor(Math.random() * count)
await Model.findOne()
.skip(random)
.exec( function (err, result) {
response[you].push(result);
console.log(response);
})
}
return response;
})
console.log(result); // Array is empty here
res.status(200).send(result);
};
I found the solution and it works for me:
exports.Run = (req, res) => {
ex1( function(rp){
console.log(rp);
res.status(200).send(rp);
});
}
function ex1(callback) {
var response = {}
var you = "you"
response[you] = [];
Model.estimatedDocumentCount().exec(async function (err, count) {
for (let i = 0; i < 8; i++) {
let random = Math.floor(Math.random() * count)
var doc = await Model.findOne().skip(random).exec();
response[you].push(doc);
}
callback(response);
})
}

Read files from directory and save to array of object

I have a directory of the tax file of employees. Each file has a filename as employee code. I am reading each file and extract some components and save to an array of employee objects.
const readline = require('readline');
let empArr = [];
function readFiles(dirname) {
fs.readdir(dirname, async function (err,filenames) {
if(err) {
return err;
}
for await (file of filenames) {
const filePath = path.join(__dirname,directoryPath,file);
const readStream = fs.createReadStream(filePath);
const fileContent = readline.createInterface({
input: readStream
});
let employeeObj = {
empId : '',
TotalEarning:'',
ProfessionalTax:0,
GrossIncome:0,
isDone:false
};
fileContent.on('line', function(line) {
if(!employeeObj.empId && line.includes("Employee:")) {
const empId = line.replace('Employee: ','').split(" ")[0];
employeeObj.empId = empId;
}
else if(line.includes('Total Earnings')) {
const amount = line.replace(/[^0-9.]/g,'');
employeeObj.TotalEarning = amount;
}
else if(line.includes('Profession Tax')) {
const amount = line.split(" ").pop() || 0;
employeeObj.ProfessionalTax = amount;
}
else if(line.includes('Gross Income')) {
const amount = line.replace(/[^0-9.]/g,'');
employeeObj.GrossIncome = amount ||0;
}
else if(line.includes('finance department immediately')) {
employeeObj.isDone =true;
empArr.push(employeeObj);
}
});
fileContent.on('close', function() {
fileContent.close();
});
}
})
}
readFiles(directoryPath);
I am not able to get empArr. After getting the array, I need to save to excel. That part I will try after getting the array of employee objects.
I got it working after reading several articles on closure and promises. The below code works for me and sends me array of employees that are processed.
const directoryPath = './tax/';
function readFiles(dirname) {
fs.readdir(dirname, async function (err,filenames) {
if(err) {
return err;
}
let promiseArr = filenames.map( file=> {
return new Promise((resolve)=>{
processFile(file, resolve)
})
});
Promise.all(promiseArr).then((ret)=>console.log(ret));
})
}
function processFile(file, callback) {
const filePath = path.join(__dirname,directoryPath,file);
const readStream = fs.createReadStream(filePath);
const fileContent = readline.createInterface({
input: readStream
});
let employeeObj = {
empId : '',
TotalEarning:'',
ProfessionalTax:0,
GrossIncome:0,
isDone:false
};
fileContent.on('line', function(line) {
if(!employeeObj.empId && line.includes("Employee:")) {
const empId = line.replace('Employee: ','').split(" ")[0];
employeeObj.empId = empId;
}
else if(line.includes('Total Earnings')) {
const amount = line.replace(/[^0-9.]/g,'');
employeeObj.TotalEarning = amount;
}
else if(line.includes('Profession Tax')) {
const amount = line.split(" ").pop() || 0;
employeeObj.ProfessionalTax = amount;
}
else if(line.includes('Gross Income')) {
const amount = line.replace(/[^0-9.]/g,'');
employeeObj.GrossIncome = amount ||0;
}
else if(line.includes('finance department immediately')) {
employeeObj.isDone = true;
return callback(employeeObj);
}
});
fileContent.on('close', function() {
fileContent.close();
});
}
readFiles(directoryPath);
Surely, the code can be improved further.

Load Array with Excel Data and Return it

Can anyone assist me with loading an array with excel data and returning it as a function? This is my initial code:
var excel = require('exceljs');
var wb = new excel.Workbook();
var path = require('path');
var filePath = path.resolve(__dirname,'data.xlsx');
function signIn(){
var SignIn = [];
wb.xlsx.readFile(filePath).then(function(){
var sh = wb.getWorksheet("Sheet1");
for(var i = 1; i < 3; i++){
SignIn.push(sh.getRow(i).getCell(2).value);
}
});
return SignIn
}
Workbook.readFile is aynchronous, you need to use either a callback or promise type approach. Using promises we can try:
var excel = require('exceljs');
var wb = new excel.Workbook();
var path = require('path');
var filePath = path.resolve(__dirname,'data.xlsx');
function signIn() {
var SignIn = [];
return wb.xlsx.readFile(filePath).then( () => {
var sh = wb.getWorksheet("Sheet1");
for(var i = 1; i < 3; i++){
SignIn.push(sh.getRow(i).getCell(2).value);
}
return SignIn;
});
}
async function testReadData() {
try {
let data = await signIn();
console.log('testReadData: Loaded data: ', data);
} catch (error) {
console.error('testReadData: Error occurred: ', error);
}
}
testReadData();
Or you can use a callback type approach:
function signInWithCallback(callback) {
var SignIn = [];
wb.xlsx.readFile(filePath).then(function(){
var sh = wb.getWorksheet("Sheet1");
for(var i = 1; i < 3; i++){
SignIn.push(sh.getRow(i).getCell(2).value);
}
callback(SignIn);
});
}
signInWithCallback((data) => console.log('Callback: Data: ', data));

Why is array length zero for a array that has contents?

Here's my code:
<script type="text/javascript" src="read.js"></script>
<script>
var beats=[]
beats=read('heartRate.txt')
console.log(beats) //label 1
console.log(beats.length) //label 2
for (i = 0; i < beats.length; i++) {
console.log(beats[i])
if(parseInt(beats[i])>80 || parseInt(beats[i])<50){
document.getElementById('Alert').innerHTML('Abnormal heartrate of '+parseInt(beats[i]))
}
}
console.log(beats)
</script>
And here is the contents of read.js:
function read(filename){
var fs = require('fs');
var readline = require('readline');
var stream = require('stream');
var str =[]
var instream = fs.createReadStream(filename);
var outstream = new stream;
var rl = readline.createInterface(instream, outstream);
rl.on('line', function(line) {
//console.log(line+'\n')
str.push(line)
});
rl.on('close', function() {
// do something on finish here
console.log(str.length)
});
return str;
}
Label 1: the value printed in the console shows the array with its contents.
Label 2: the length of the array is shown as 0.
Is there any way to find the size of the array?
The console image is attached here:
I guess it is because of the read() function is asynchronous and it will take some time to finish the execution. Initially, the length was printed as zero then came the actual value 5. Try to return a promise from read() function and see how it works.
function async read(filename){
var fs = require('fs');
var readline = require('readline');
var stream = require('stream');
var str =[]
var instream = fs.createReadStream(filename);
var outstream = new stream;
var rl = readline.createInterface(instream, outstream);
rl.on('line', function(line) {
//console.log(line+'\n')
str.push(line)
});
rl.on('close', function() {
// do something on finish here
console.log(str.length)
});
return str;
}
<script type="text/javascript" src="read.js"></script>
<script>
var beats=[]
read('heartRate.txt').then(function(data){
beats=data
//do your stuff here
})
</script>
Wont work beacuse,
console.log(beats) //label 1
console.log(beats.length)
Reading happens asynchronously, the push would execute only after,
rl.on('line', function(line) {
//console.log(line+'\n')
str.push(line)
});
Add it on the close (rl.on('close',).
You should make read return a promise and only use the data when it's finished loading all data:
function read(filename){
return new Promise((resolve, reject) => {
const fs = require("fs");
const readable = fs.createReadStream(filename);
let data = [];
readable.on('data', chunk => {
data.push(chunk);
});
readable.on('end', () => {
resolve(data);
});
readable.on('error', err => {
reject(err);
});
}
}
You can use it like this:
<script type="text/javascript" src="read.js"></script>
<script>
read('heartRate.txt').
then(beats => {
console.log(beats) //label 1
console.log(beats.length) //label 2
for (i = 0; i < beats.length; i++) {
console.log(beats[i])
if(parseInt(beats[i])>80 || parseInt(beats[i])<50){
document.getElementById('Alert').innerHTML(`Abnormal heartrate of ${parseInt(beats[i])} beats`);
}
}
console.log(beats)
})
.catch(err => console.log(`Oh no, an error has occurred: ${err} `));
</script>

I would like to analyze the image with tensorflw.js - nodejs

mobilenet.js
var loadFrozenModel = require('#tensorflow/tfjs-converter');
var NamedTensorMap = require('#tensorflow/tfjs-converter');
var tfc = require('#tensorflow/tfjs-core');
var IMAGENET_CLASSES = require('./imagenet_classes');
const GOOGLE_CLOUD_STORAGE_DIR = 'https://storage.googleapis.com/tfjs-models/savedmodel/';
const MODEL_FILE_URL = 'mobilenet_v1_1.0_224/optimized_model.pb';
const WEIGHT_MANIFEST_FILE_URL = 'mobilenet_v1_1.0_224/weights_manifest.json';
const INPUT_NODE_NAME = 'input';
const OUTPUT_NODE_NAME = 'MobilenetV1/Predictions/Reshape_1';
const PREPROCESS_DIVISOR = tfc.scalar(255 / 2);
class MobileNet {
constructor() {}
async load() {
this.model = await loadFrozenModel(
GOOGLE_CLOUD_STORAGE_DIR + MODEL_FILE_URL,
GOOGLE_CLOUD_STORAGE_DIR + WEIGHT_MANIFEST_FILE_URL);
}
dispose() {
if (this.model) {
this.model.dispose();
}
}
predict(input) {
const preprocessedInput = tfc.div(
tfc.sub(input.asType('float32'), PREPROCESS_DIVISOR),
PREPROCESS_DIVISOR);
const reshapedInput =
preprocessedInput.reshape([1, ...preprocessedInput.shape]);
const dict = {};
dict[INPUT_NODE_NAME] = reshapedInput;
return this.model.execute(dict, OUTPUT_NODE_NAME);
}
getTopKClasses(predictions, topK) {
const values = predictions.dataSync();
predictions.dispose();
let predictionList = [];
for (let i = 0; i < values.length; i++) {
predictionList.push({value: values[i], index: i});
}
predictionList = predictionList
.sort((a, b) => {
return b.value - a.value;
})
.slice(0, topK);
return predictionList.map(x => {
return {label: IMAGENET_CLASSES[x.index], value: x.value};
});
}
}
module.exports = MobileNet;
test.js
var tfc = require('#tensorflow/tfjs-core');
var MobileNet = require('./mobilenet');
var fs = require('fs');
var image = require('get-image-data')
var i = 0;
var meta;
image('./cat.jpg', function(err, getImageData){
if(err) throw err;
console.log('start to image data ');
console.log(i++);
console.log("meta : " + getImageData.data.length);
console.log("getImageData :"+getImageData);
const mobileNet = new MobileNet();
console.time('Loading of model');
// await mobileNet.load();
console.timeEnd('Loading of model');
console.log("maybee this is error on the data type");
const pixels = tfc.fromPixels(image);
console.time('First prediction');
let result = mobileNet.predict(pixels);
const topK = mobileNet.getTopKClasses(result, 5);
console.timeEnd('First prediction');
resultElement.innerText = '';
topK.forEach(x => {
resultElement.innerText += `${x.value.toFixed(3)}: ${x.label}\n`;
});
console.time('Subsequent predictions');
result = mobileNet.predict(pixels);
mobileNet.getTopKClasses(result, 5);
console.timeEnd('Subsequent predictions');
mobileNet.dispose();
});
I want to analyze the image using the tensorflow.js.
But it doesn't work.
ReferenceError: ImageData is not defined
at MathBackendCPU.fromPixels (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/kernels/backend_cpu.js:75:31)
at Engine.fromPixels (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/engine.js:292:29)
at ArrayOps.fromPixels (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/ops/array_ops.js:195:41)
at /Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/ops/operation.js:11:61
at Object.Tracking.tidy (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/tracking.js:36:22)
at Object.descriptor.value [as fromPixels] (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/#tensorflow/tfjs-core/dist/ops/operation.js:11:26)
at /Users/leeyongmin/Documents/tfjs-converter-master-2/demo/test.js:26:22
at /Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/get-image-data/index.js:18:7
at load (/Users/leeyongmin/Documents/tfjs-converter-master-2/demo/node_modules/get-image/server.js:18:5)
at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:511:3)

Categories

Resources