I want to find string sequence with rxjs - javascript

I want to find string sequence with rxjs
for example
Target string: 01234010
Match stringe: 01
answer = 2
I have a solution with using javascript
let index = 0;
while (true) {
let foundIndex = targetSequence.indexOf(matchSequence, index);
if (foundIndex == -1) break;
index = foundIndex + 1;
}
but the problem is that I have to use rxjs with those skeleton code
import { from, Observable } from "rxjs";
const targetSequence = `01234010`;
const matchSequence = "01";
const _target = from(targetSequence);
const _output: Observable<number> = _target.pipe(
// here is your code
);
_output.subscribe({
next: val => console.log(`count : ${val}`)
});
do you guys have any idea?

For this, you could use the rxJS operator map.
E.g.
const targetSequence = '01234010';
const matchSequence = '01';
const _target = of(targetSequence);
const _output = _target.pipe(
map((val) => {
let foundIndex = val.indexOf(matchSequence);
return foundIndex + matchSequence.length;
})
);
_output.subscribe({next: (val) => console.log(val)})
Note: I've used the of method to generate the observable, using from emitted for each character. I've also slightly modified your method of finding the result but I think it achieves what you want.

Related

Adding inputs to a `tf.data.generator` in tensorflow.js

I'm trying to create a data generator, which I verified was working by itself in pure js. TFJS documentation for it is here, with two examples:
https://js.tensorflow.org/api/latest/#data.generator
I'd like to use a tf.data.generator as this datasets requires elaborate preprocessing. A minimal example is as follows:
const tf = require('#tensorflow/tfjs-node');
class dataGeneratorGenerator {
constructor(test) {
this.test = test
}
* dataGenerator() {
let len = this.test.length
let idx = 0
while (idx < len) {
idx++
console.log(idx)
yield this.test[idx]
}
}
}
let dgg = new dataGeneratorGenerator(['hi', 'hi2', 'hi3'])
let trainDs = tf.data.generator(dgg.dataGenerator);
trainDs.forEachAsync(e => console.log(e));
The error is as follows:
TypeError: Error thrown while iterating through a dataset: Cannot read property 'test' of undefined
Iterating through our datagenerator in pure javascript works:
let dgg = new dataGeneratorGenerator(['hi', 'hi2', 'hi3'])
let dg = dgg.dataGenerator()
console.log(dgg.next())
console.log(dgg.next())
console.log(dgg.next())
My understanding is that we are only passing dataGenerator into tf.data.generator instead of the entire class. Then, how is it possible to input variables into tf.data.generator? Thanks.
One can simply use an arrow function.
const tf = require('#tensorflow/tfjs-node');
function* dataGenerator(test) {
let len = test.length
let idx = 0
while (idx < len) {
idx++
console.log(idx)
}
}
let trainDs = tf.data.generator(() => dataGenerator(['hi', 'hi2', 'hi3']));
trainDs.forEachAsync(e => console.log(e));

Why i keep getting NaN value in my tip calculator?

I can't find out what is going wrong in my code. Thank you.
I have attached the link to code via codepen.
https://codepen.io/tenzin12/pen/rNmmPbv
`const confirmBtn = document.querySelector(".confirm");
const tipField = document.querySelector(".p1");
const totalField = document.querySelector(".p2");
const tipPercentage = document.querySelector("#tip").children;
const customTip = document.querySelector(".custom").value;
const inputAmt = document.querySelector("#amount").value;
const totalPerson = document.querySelector(".number_of_people").value;
const calcFunction = (bill, percent, diners) => {
const percentage = percent / 100;
const tipPerPerson = (bill * percentage) / diners;
const finalBillPerPerson = bill / diners;
const finalWithTip = finalBillPerPerson + tipPerPerson;
tipField.textContent = tipPerPerson;
totalField.textContent = finalWithTip;
};
for (let i = 0; i < tipPercentage.length; i++) {
tipPercentage[i].addEventListener("click", () => {
if (parseInt(totalPerson) > 0) {
if (tipPercentage[i].value.toUpperCase() === "CUSTOM") {
calcFunction(parseFloat(inputAmt), parseInt(customTip), parseInt(totalPerson));
}
}
calcFunction(parseFloat(inputAmt), parseInt(tipPercentage[i].value), parseInt(totalPerson));
});
}
`
When you need to run calculations on element values, you need to collect those values at the time of calculation. You were collecting them up front - but then when you were calculating the function, it was using those old values. I moved those into your function. Note how I got rid of most of the parseInt and parseFloat functions in favor of the minimal + operator which does the same thing.
Additionally, I simplified the code a little and put in a validation to prevent totals being run on 0 people or 0 amounts. Finally, I changed your for loop into an HTMLCollection forEach loop. I find it is easier to read and maintain
const confirmBtn = document.querySelector(".confirm");
const tipField = document.querySelector(".p1");
const totalField = document.querySelector(".p2");
const tipPercButtons = document.querySelectorAll("#tip input.percentage");
const calcFunction = (bill, percent, diners) => {
const percentage = percent / 100;
const tipPerPerson = (bill * percentage) / diners;
const finalBillPerPerson = bill / diners;
const finalWithTip = finalBillPerPerson + tipPerPerson;
tipField.textContent = tipPerPerson;
totalField.textContent = finalWithTip;
};
tipPercButtons.forEach((el) =>
el.addEventListener("click", (e) => {
const customTip = +document.querySelector(".custom").value;
const inputAmt = +document.querySelector("#amount").value;
const totalPerson = +document.querySelector(".number_of_people").value;
if (isNaN(totalPerson) || isNaN(inputAmt)) {
alert("Please designate the number of people and the amount of the bill")
return;
}
if (totalPerson === 0) return;
let val
if (e.target.value.toUpperCase() === "CUSTOM") val = customTip;
else val = parseInt(e.target.value);
calcFunction(inputAmt, val, totalPerson);
})
);
Updated pen: https://codepen.io/john-tyner/pen/MWmmLMQ?editors=1111
i analysed your code there is some error in fetching the input value in the code.
below is the correct code. Hope this might work
make the following little changes in your code:
const inputAmt = document.querySelector("#amount");
const totalPerson = document.querySelector(".number_of_people");
and this at the bottom outside the if block
calcFunction(
parseFloat(inputAmt.value),
parseInt(tipPercentage[i].value),
parseInt(totalPerson.value)
);
overall your calculator is So interesting.

Using data i get from request function in node.JS again until a condition is met

I want to access shopify api using Node.js with request method. I get first 50 items but i need to send the last id of the products i get as a response so it can loop through all the products until we don't have another id (i check that if the last array is not 50 in length.)
So when i get the response of lastID i want to feed that again to the same function until the Parraylength is not 50 or not 0.
Thing is request works asynchronously and i don't know how to feed the same function with the result lastID in node.js.
Here is my code
let importedData = JSON.parse(body);
//for ( const product in importedData.products ){
// console.log(`${importedData.products[product].id}`);
//}
lastID = importedData.products[importedData.products.length-1].id;
let lastIDD = lastID;
console.log(`This is ${lastID}`);
importedData ? console.log('true') : console.log('false');
let Prarraylength = importedData.products.length;
console.log(Prarraylength);
//console.log(JSON.stringify(req.headers));
return lastIDD;
});```
You can use a for loop and await to control the flow of your script in this case.
I'd suggest using the request-native-promise module to get items, since it has a promise based interface, but you could use node-fetch or axios (or any other http client) too.
In this case, to show you the logic, I've created a mock rp which normally you'd create as follows:
const rp = require("request-promise-native");
You can see we're looping through the items, 50 at a time. We're passing the last id as a url parameter to the next rp call. Now this is obviously going to be different in reality, but I believe you can easily change the logic as you require.
const totalItems = 155;
const itemsPerCall = 50;
// Mock items array...
const items = Array.from({ length: totalItems}, (v,n) => { return { id: n+1, name: `item #${n+1}` } });
// Mock of request-promise (to show logic..)
// Replace with const rp = require("request-promise-native");
const rp = function(url) {
let itemPointer = parseInt(url.split("/").slice(-1)[0]);
return new Promise((resolve, reject) => {
setTimeout(() => {
let slice = items.slice(itemPointer, itemPointer + itemsPerCall);
itemPointer += itemsPerCall;
resolve( { products: slice });
}, 500);
})
}
async function getMultipleRequests() {
let callIndex = 0;
let lastID = 0;
const MAX_CALLS = 20;
const EXPECTED_ARRAY_LENGTH = 50;
for(let callCount = 1; callCount < MAX_CALLS; callCount++) {
// Replace with the actual url..
let url = "/products/" + lastID;
let importedData = await rp(url);
lastID = importedData.products[importedData.products.length - 1].id;
console.log("Call #: " + ++callIndex + ", Item count: " + importedData.products.length + ", lastID: " + lastID);
if (importedData.products.length < EXPECTED_ARRAY_LENGTH) {
console.log("Reached the end of products...exiting loop...");
break;
}
}
}
getMultipleRequests();

How do I optimize this synchronous "fuzzy search" function and turn it into an async function?

Problem
I'm trying to implement some sort of "fuzzy search" in my Node.js based project.
Fuzzy search is a search that returns results even if the string didn't match exactly.
I found this code in another stackoverflow thread. Code is below.
It's quite good, but the problem is - it's synchronous It slows down the whole program when it searches through a large array.
Question
ES6 methods are welcomed. Needs to work only in the latest Chrome, so any JS methods will work.
Are there any new JS methods that would optimize this function?
Am I doing something wrong there that makes it even slower?
Can I turn this function into an async function that returns a promise? Will it stop freezing the app during the search then?
Are there any better "fuzzy search" implementations you know of? (I found a module called fuzzysort, can't say if it's that much better though, it won't return "folder test" if you type "test folder" (wrong order) so it's not that good)
Code
Calling search function
searchArray is an array of paths it searches through, e.g.: ["C:\\test", "C:\\file.txt"...] (0.5 - 5 million paths)
searchQuery is a string without spaces, e.g.: filetxt
search () {
const fuzzySearch = this.fuzzySearch(this.searchQuery.toLowerCase(), this.searchArray)
let result = fuzzySearch.filter(element => element.relevance >= 0.3)
// sort by relevance
var sortedResults = result.sort((a, b) => parseFloat(b.relevance) - parseFloat(a.relevance)).map(item => item.name);
this.searchResults = sortedResults
},
The fuzzy search function
fuzzySearch (searchQuery, searchArray) {
const get_bigrams = function(string) {
const s = string.toLowerCase();
const v = new Array(s.length - 1);
for (let i = 0, end = v.length; i <= end; i++) {
v[i] = s.slice(i, i + 2);
}
return v;
};
const string_similarity = function(str1, str2) {
if ((str1.length > 0) && (str2.length > 0)) {
const pairs1 = get_bigrams(str1);
const pairs2 = get_bigrams(str2);
const union = pairs1.length + pairs2.length;
let hit_count = 0;
for (let x of Array.from(pairs1)) {
for (let y of Array.from(pairs2)) {
if (x === y) {
hit_count++;
}
}
}
if (hit_count > 0) {
return ((2.0 * hit_count) / union);
}
}
return 0.0;
};
let results = [];
for (let name of searchArray) {
// I added .match to use only the base filename (name+ext) not the whole path, and removed all characters
let filteredPath = name.match(/[^\\\/]+$/)[0].replace(/[^A-Za-z0-9.]+/g, '')
const relevance = string_similarity(searchQuery, filteredPath);
const obj = {name, relevance};
results.push(obj);
}
return results
},

CSV separator auto-detection in Javascript

How can I detect the CSV separator from a string in Javascript/NodeJS?
Which is the standard algorithm?
Note that the separator is not a comma always. The most common separators being ;, , and \t (tab).
A possible algorithm for getting the likely separator(s) is pretty simple, and assumes the data is well-formed:
For every delimiter,
For every line,
Split the line by the delimiter, check the length.
If its length is not equal to the last line's length, this is not a valid delimiter.
Proof of concept (doesn't handle quoted fields):
function guessDelimiters (text, possibleDelimiters) {
return possibleDelimiters.filter(weedOut);
function weedOut (delimiter) {
var cache = -1;
return text.split('\n').every(checkLength);
function checkLength (line) {
if (!line) {
return true;
}
var length = line.split(delimiter).length;
if (cache < 0) {
cache = length;
}
return cache === length && length > 1;
}
}
}
The length > 1 check is to make sure the split didn't just return the whole line. Note that this returns an array of possible delimiters - if there's more than one item, you have an ambiguity problem.
Another solution is using the detect method from the csv-string package:
detect(input : String) : String Detects the best separator.
var CSV = require('csv-string');
console.log(CSV.detect('a,b,c')); // OUTPUT : ","
console.log(CSV.detect('a;b;c')); // OUTPUT : ";"
console.log(CSV.detect('a|b|c')); // OUTPUT : "|"
console.log(CSV.detect('a\tb\tc'));// OUTPUT : "\t"
function delimiter(csvText) {
t = t.split("\n")[0];
let delArray = [',', ';', '|', ' '];
let comma = samiclon = pipe = tab = 0;
delArray.forEach((e, i) => {
if (i === 0) {
comma = t.split(e).length;
} else if (i === 1) {
samiclon = t.split(e).length;
} else if (i === 2) {
pipe = t.split(e).length;
} else if (i === 3) {
tab = t.split(e).length;
}
});
let tmpArray1 = [comma, samiclon, pipe, tab]
let tmpArray = [comma, samiclon, pipe, tab];
let maxLen = tmpArray.sort((a, b) => b - a)[0];
let delimiter_i = 0;
tmpArray1.forEach((e, i) => {
if (maxLen === e) {
delimiter_i = i;
}
});
if (delimiter_i === 0) {
return ',';
} else if (delimiter_i === 1) {
return ';'
} else if (delimiter_i === 2) {
return '|'
} else if (delimiter_i === 3) {
return ' '
}
}
This solution allows to detect the csv separator only for the top lines and handles quoted fields by using csv-parse.
It can be useful for large csv file to avoid reading the whole file several times.
const parse = require('csv-parse/lib/sync');
const fs = require('fs')
function detectCsvDelimiter(file, maxLineCount, delimiters = [',', ';', '\t']) {
return new Promise((resolve, reject) => {
// Read only maxLineCount lines
let stream = fs.createReadStream(file, {
flags: 'r', encoding: 'utf-8', bufferSize: 64 * 1024 });
let lineCounter = 0;
let data = '';
stream.on("data", (moreData) => {
data += moreData;
lineCounter += data.split("\n").length - 1;
if (lineCounter > maxLineCount + 1) {
stream.destroy();
// Remove invalid last line
resolve(data.split('\n').slice(0, maxLineCount));
}
});
stream.on("error", (err) => reject(err));
stream.on("end", () => resolve(data.split("\n")));
}).then(lines => {
return new Promise(resolve => {
const csvData = lines.join("\n");
const validDelimiters = delimiters.filter(delimiter => {
let isValid = true;
// csv-parse throw error by default
// if the number of columns is inconsistent between lines
try {
const rows = parse(csvData, {delimiter});
isValid = rows.some(row => row.length > 1);
} catch (e) {
isValid = false;
}
return isValid;
});
resolve(validDelimiters);
});
});
}
I found Zirak's answer good in theory, but in practice it failed in many particular places.
Here are some examples that would fail and thus the method would return no delimiter :
a trailing delimiter (by mistake) : test,test1,test2,
missing cells without delimiters: test,test1
This is the most convenient and elegant solution :
let columnData = row.split(/,|;|\|| /);
What sucks here is if there is two delimiters that appear in a row, then this fails.
Say you want to seperate this data: "test,tes|t1,test2".
The above code produces an array that looks like this :
[test, tes, t1, test2]... No good.
Here is a more robust solution I wrote that was inspired by "the programmers" answer:
const rowSplitChars = this.determineCSVLineBreak(text);
const columnSplitChars = this.determineCSVDelimiter(text, rowSplitChars);
private determineCSVLineBreak(text: any): string {
try {
const delArray = ["\r\n", "\n", "\r"];
const rnrnArray =
[text.match(/\r/g).length
,text.match(/\n/g).length
,text.match(/\r\n/g).length];
return delArray[this.getMaxIndexInArray(rnrnArray)];
} catch {
this.handleError('Error determining CSV file line break character.');
return '';
}
}
private determineCSVDelimiter(text: any, rowSplitChars: string): string {
const t = text.split(rowSplitChars)[0];
const delArray = [',', ';', '|', ' '];
const countArray =
[t.split(delArray[0]).length
,t.split(delArray[1]).length
,t.split(delArray[2]).length
,t.split(delArray[3]).length];
return delArray[this.getMaxIndexInArray(countArray)];
}
private getMaxIndexInArray(countArray: any[]) {
let max = countArray[0];
let maxIndex = 0;
for (let i = 1; i < countArray.length; i++) {
if (countArray[i] > max) {
maxIndex = i;
max = countArray[i];
}
}
return maxIndex;
}

Categories