I am wondering if there is a way by which I can convert a format, let's say a tree to a format I want. Take the following example:
a -> b, d
f - > c
f-> v
I want to have this as an output:
a implies (b and d)
f implies (c or v)
This is practically the algorithm that you are looking for, but please take note that this algorithm doesn't support the deep conditions.
function mathLogic(inputs) {
var rows = inputs.split("\n");
for (var i in rows)
rows[i] = rows[i].replace(/\s/g, "");
console.log("Rows: ", rows)
var logics = {};
for (var i in rows) {
var row = rows[i];
var rowSplit = row.split("->");
var from = rowSplit[0];
var to = rowSplit[1];
var ands = to.split(",");
if (!logics[from])
logics[from] = [];
logic = logics[from];
logic.push(ands);
}
for (var i in logics) {
var implyString = i + " implies ";
var orLogic = logics[i];
var ors = [];
for (var j in orLogic) {
var or = orLogic[j]
if (or.length > 1)
ors.push("(" + or.join(" and ") + ")");
else
ors.push(or.join(" and "));
}
if (ors.length > 1)
implyString += "(" + ors.join(" or ") + ")";
else
implyString += ors.join(" or ");
console.log(implyString);
}
}
mathLogic(`a -> b, d
f - > c
f-> v`);
Related
How to read Column wise values from excel using nodejs(node-xlsx) ? Please advise.
I want to read Col A data, then Col B and so on, if any data exists in other columns, then put data in array.
I am able to read A1, B1, A2, B2... this way but not A1, A2, A3... then B1, B2, B3... etc.
Sample column wise data
I did custom way but not able to go to col C dynamically.
const xlsxfile = require("xlsx");
var arr = [];
const spreadsheet = xlsxfile.readFile('./Code.xlsx');
const sheets = spreadsheet.SheetNames;
console.log('Sheet Names -- ' + sheets);
const firstSheetName = sheets[0];
const firstSheet = spreadsheet.Sheets[firstSheetName];
console.log(firstSheet);
for (z in firstSheet) {
if (z[0] === '!') continue;
//parse out the column, row, and value
var tt = 0;
for (var i = 0; i < z.length; i++) {
if (!isNaN(z[i])) {
tt = i;
break;
}
};
var col = z.substring(0, tt);
var row = parseInt(z.substring(tt));
for (; ; row++) { // looping over all rows in a column
const firstCol = firstSheet[col+''+row];
if (!firstCol) {
break;
}
let value = firstCol.w;
//console.log(value);
if (value)
if (!arr.includes(value))
arr.push(value);
else
continue;
else
break;
}
}
console.log('final array = '+arr);
I somehow achieved my goal in very bad way. In top most loop it's always trying to get A1, B1, C1 like that. But in between I hijacked and looping all rows.
So in that way, I am keeping one track of what's my last column and comparing in next is same column or new column. if same column, I am existing.
But is there any better way to get all values may be in array format column wise?
const xlsxfile = require("xlsx");
var arr = [];
const spreadsheet = xlsxfile.readFile('./Code.xlsx');
const sheets = spreadsheet.SheetNames;
console.log('Sheet Names -- ' + sheets);
const firstSheetName = sheets[0];
const firstSheet = spreadsheet.Sheets[firstSheetName];
console.log(firstSheet);
let earliercol = []; // keeping a track
for (z in firstSheet) {
if (z[0] === '!') continue;
//parse out the column, row, and value
let tt = 0;
for (let i = 0; i < z.length; i++) {
if (!isNaN(z[i])) {
tt = i;
break;
}
};
let col = z.substring(0, tt);
let row = parseInt(z.substring(tt));
if (earliercol.includes(col)) // checking current col already traversed or not
break;
earliercol.push(col); // assigning current col name
//var value = worksheet[z].v;
for (; ; row++) {
//const firstCol = firstSheet['A' + i];
const firstCol = firstSheet[col+''+row];
if (!firstCol) {
break;
}
let value = firstCol.w;
//console.log(value);
if (value)
if (!arr.includes(value))
arr.push(value);
else
continue;
else
break;
}
}
console.log('final array = '+arr);
Wanted to check if there is any null value in column field in the csv file and also there shouldn't be null value after / in number column, if it is null the entire row should not be written to output file.
name,number,gender,country
iva 1/001 f Antartica
aaju 2/002 m russia
lax 3/ m brazil
ana 4/004 f Thailand
vis 5/005 m
for e.g. 3rd and 5th row should not be written to output file.
using (StreamWriter file = new StreamWriter(filepathop)) {
for (int i = 0; i < csv.Length; i++) {
{
if (i == 0) {
file.WriteLine(header + "," + "num" + "," + "serial" + "," + "date");
}
else {
var newline = new StringBuilder();
string[] words = csv[i].Split(',');
string[] no = words[1].Split('/');
string number = no[0];
string serial = no[1];
newline.Append(number + "," + serial + "," + tokens[0]);
file.WriteLine(csv[i] + "," + newline);
}
}
}
}
}
}
}
You can test for null columns with string.IsNullOrEmpty(column) or column.Length == 0 like so:
if (!string.IsNullOrEmpty(serial) && !string.IsNullOrEmpty(country))
file.WriteLine(csv[i] + "," + newline);
You might want to check and remove white space, too. Depends on your input.
I need a fast method to find all indices of a search term that might occur in a string. I tried this 'brute force' String extension method:
// Note: makes use of ExSwift
extension String
{
var length: Int { return count(self) }
func indicesOf(searchTerm:String) -> [Int] {
var indices = [Int]()
for i in 0 ..< self.length {
let segment = self[i ... (i + searchTerm.length - 1)]
if (segment == searchTerm) {
indices.append(i)
}
}
return indices;
}
}
... But it's ridiculously slow, especially the shorter the search term is. What would be a better method to find all indices fast?
As Martin said you can implement some of the well known fastest algorithms in String Matching, The Knuth–Morris–Pratt string searching algorithm (or KMP algorithm) searches for occurrences of a "word" W within a main "text string" S.
The algorithm has complexity O(n), where n is the length of S and the O is big-O notation.
extension String {
// Build pi function of prefixes
private func build_pi(str: String) -> [Int] {
var n = count(str)
var pi = Array(count: n + 1, repeatedValue: 0)
var k = -1
pi[0] = -1
for (var i = 0; i < n; ++i) {
while (k >= 0 && str[k] != str[i]) {
k = pi[k]
}
pi[i + 1] = ++k
}
return pi
}
// Knuth-Morris Pratt algorithm
func searchPattern(pattern: String) -> [Int] {
var matches = [Int]()
var n = count(self)
var m = count(pattern)
var k = 0
var pi = build_pi(pattern)
for var i = 0; i < n; ++i {
while (k >= 0 && (k == m || pattern[k] != self[i])) {
k = pi[k]
}
if ++k == m {
matches.append(i - m + 1)
}
}
return matches
}
subscript (i: Int) -> Character {
return self[advance(self.startIndex, i)]
}
}
Then you can use it in the following way:
var string = "apurba mandal loves ayoshi loves"
var pattern = "loves"
println(string.searchPattern(pattern))
An the output should be :
[14, 27]
That belong to the start index of the pattern occurrences inside the the string. I hope this help you.
EDIT:
As Martin said in his comment you need to avoid the use of the advance function to index an String by an Int because it's O(position to index).
One possible solution is to convert the String to an array of Character and then access to the indexes is O(1).
Then the extension can be changed to this one :
extension String {
// Build pi function of prefixes
private func build_pi(str: [Character]) -> [Int] {
var n = count(str)
var pi = Array(count: n + 1, repeatedValue: 0)
var k = -1
pi[0] = -1
for (var i = 0; i < n; ++i) {
while (k >= 0 && str[k] != str[i]) {
k = pi[k]
}
pi[i + 1] = ++k
}
return pi
}
// Knuth-Morris Pratt algorithm
func searchPattern(pattern: String) -> [Int] {
// Convert to Character array to index in O(1)
var patt = Array(pattern)
var S = Array(self)
var matches = [Int]()
var n = count(self)
var m = count(pattern)
var k = 0
var pi = build_pi(patt)
for var i = 0; i < n; ++i {
while (k >= 0 && (k == m || patt[k] != S[i])) {
k = pi[k]
}
if ++k == m {
matches.append(i - m + 1)
}
}
return matches
}
}
Instead of checking for the search term at each position of the string
you could use rangeOfString() to find the next occurrence (hoping
that rangeOfString() uses more advanced algorithms):
extension String {
func indicesOf(searchTerm:String) -> [Int] {
var indices = [Int]()
var pos = self.startIndex
while let range = self.rangeOfString(searchTerm, range: pos ..< self.endIndex) {
indices.append(distance(self.startIndex, range.startIndex))
pos = range.startIndex.successor()
}
return indices
}
}
Generally, it depends on the size of the input string and the size
of the search string which algorithm is "the fastest". You'll find
an overview with links to various algorithms in
String searching algorithm.
Update for Swift 3:
extension String {
func indices(of searchTerm:String) -> [Int] {
var indices = [Int]()
var pos = self.startIndex
while let range = range(of: searchTerm, range: pos ..< self.endIndex) {
indices.append(distance(from: startIndex, to: range.lowerBound))
pos = index(after: range.lowerBound)
}
return indices
}
}
Using NSRegularExpression in Swift 4, you can do it like this. NSRegularExpression has been around forever and is probably a better choice than rolling your own algorithm for most cases.
let text = "The quieter you become, the more you can hear."
let searchTerm = "you"
let regex = try! NSRegularExpression(pattern: searchTerm, options: [])
let range: NSRange = NSRange(text.startIndex ..< text.endIndex, in: text)
let matches: [NSTextCheckingResult] = regex.matches(in: text, options: [], range: range)
let ranges: [NSRange] = matches.map { $0.range }
let indices: [Int] = ranges.map { $0.location }
let swiftRanges = ranges.map { Range($0, in: text) }
let swiftIndices: [String.Index] = swiftRanges.flatMap { $0?.lowerBound }
I'm trying to add together two large numbers, stored as strings.
Here's what I have so far:
function addBigNums(a,b){
c = ""; // output
o = 0; // carryover
startLen = a.length-1;
for(i = startLen; i >= 0; i--) {
sum = parseInt(a[i], 10) + parseInt(b[i], 10) + o;
c = (sum % 10) + c;
o = sum >= 10;
}
if(o === true) c = "1" + c;
return c;
}
I'm running into two issues:
1 ) my carry is not always functioning properly, primarily when:
2 ) the numbers length differ.
Right now I think I would have to prepend 0's onto the shorter number in order to get this to function as expected.
Any better alternatives to this?
Simple, straightforward integer addition like you would do it manually:
a = "123456"; // input a
b = "123456"; // input b
c = ""; // target-string
o = 0; // overflow-bit
// traverse string from right to left
for(i = a.length - 1; i >= 0; i--) {
// do the calculation (with overflow bit)
sum = parseInt(a[i]) + parseInt(b[i]) + o;
// prepend resulting digit to target
c = (sum % 10) + c;
// set overflow bit for next round
o = sum >= 10;
}
// prepend another "1" if last overflow-bit is true
if(o == true) c = "1" + c;
If strings a and b are not equal length (but you stated that they are), you should prepend the shorter string with zeros before calculation.
Consider both numbers to be an array of digits. Add them up right-to-left handling overflow flag. Demo. Assuming your numbers are of the same length
function getNumber(len) {
return Array.apply(null, new Array(len)).map(function(){
return Math.floor(Math.random()*9);
}).join('');
}
var len = 600,
a = getNumber(len), //use your numbers here
b = getNumber(len),
flag = 0;
var c = [].reduceRight.call(a, function(acc, val, idx) {
val = +val + (+b.charAt(idx)) + flag;
flag = val / 10 | 0;
val %= 10;
return val + acc;
}, '');
c = (flag ? 1: '') + c;
console.log(a, b, c);
I've written a script in google docs to use =importXML function and return the value on its own rather than leaving the function there loading on opening and every hour slowing the thing down.
Basically it uses the data in row D (hidden), sticks the formula in B2, then, overwrites B2 with the value of the formula. I then wanted to repeat this going down the list but just didn't know how - currently I've just repeated the function and changed the cell ID, which I'm aware is a travesty. Could someone guide a noob on how to do it efficiently?
function pullValues()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var cellref1 = sheet.getRange("D2");
var ID = cellref1.getValue();
var apistring = "http://api.eve-central.com/api/marketstat?usesystem=30000142&typeid=" + ID;
var command = "importxml(\"" + apistring + "\", \"/evec_api/marketstat/type/sell/min\")";
var cellref2 = sheet.getRange("B2");
cellref2.setFormula(command);
var val = cellref2.getValue();
cellref2.setValue(val);
}
https://docs.google.com/spreadsheet/ccc?key=0AjZlH_sGnj6vdDU4QWdyZTVTd2E4RUFXZnVEZlZJS3c#gid=0
You have to iterate through all rows in the spreadsheet using a for loop. There are many ways to do it, the following code is one of them:
function pullValues()
{
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var startRow = 2; // First row of data to process
var lastRow = sheet.getLastRow(); // Last row of data to process
for (var i = startRow; i <= lastRow; i++)
{
var cellref1 = sheet.getRange("D" + i);
var ID = cellref1.getValue();
var apistring = "http://api.eve-central.com/api/marketstat?usesystem=30000142&typeid=" + ID;
var command = "=ImportXML(\"" + apistring + "\", \"/evec_api/marketstat/type/sell/min\")";
var cellref2 = sheet.getRange("B" + i);
cellref2.setFormula(command);
var val = cellref2.getValue();
cellref2.setValue(val);
}
}