Code Challenge: Rename filenames if duplicates are present - javascript

I'm working through a coding challenge I found online. I have the first test case passing but failing the second. I'm trying to decide if the second test case I'm failing is a typo or not.
Here is the question:
You are given an array of desired filenames in the order of their
creation. Since two files cannot have equal names, the one which comes
later will have an addition to its name in a form of (k), where k is
the smallest positive integer such that the obtained name is not used
yet.
Return an array of names that will be given to the files.
Test Cases:
1 - Passing:
INPUT: ["doc", "doc", "image", "doc(1)", "doc"]
OUTPUT: ["doc", "doc(1)", "image", "doc(1)(1)", "doc(2)"]
2 - Failing:
INPUT: ["a(1)","a(6)","a","a","a","a","a","a","a","a","a","a"]
OUTPUT: ["a(1)","a(6)","a","a(2)","a(3)","a(4)","a(5)","a(7)","a(8)","a(9)","a(10)","a(11)"]
Here is my code that passes the first Spec:
function fileNaming(names) {
var finalArr = [],
obj = {};
names.forEach(function(val){
if(obj[val] === undefined){
if(finalArr.indexOf(val) === -1){
finalArr.push(val);
obj[val] = 0;
} else {
obj[val] = 1;
finalArr.push(val + "(" + obj[val] + ")" );
}
} else {
finalArr.push( val + "(" + (++obj[val]) + ")");
}
});
return finalArr;
}
Question:
In the second test spec, why isn't there an "a(1)(1)" like there is a "doc(1)(1)" Is this a typo?
If anyone has suggestions on improvining my approach or alternative approaches I would greatly appreciate your feedback.

Here's a simpler approach. The idea is to store both the original and the generated name in the hashtable:
f = function(xs) {
var c = {}, t = (x, n) => x + "(" + n + ")";
return xs.map(function(x) {
var n = c[x] || 0;
c[x] = n + 1;
if(!n)
return x;
while(c[t(x, n)])
n++;
c[t(x, n)] = 1;
return t(x, n);
});
};
q = ["doc", "doc", "image", "doc(1)", "doc", "doc"];
document.write('<pre>'+JSON.stringify(f(q)));
q = ["a(1)","a(6)","a","a","a","a","a","a","a","a","a","a"]
document.write('<pre>'+JSON.stringify(f(q)));

Here's my approach :
def fileNaming(names):
uniq = []
for i in range(len(names)):
if names[i] not in uniq:
uniq.append(names[i])
else:
k = 1
while True:
if (names[i] + "(" + str(k) + ")") in uniq:
k += 1
else:
uniq.append(names[i] + "(" + str(k) + ")")
break
return uniq

with arrray approch
//var arr=["doc", "doc", "image", "doc(1)", "doc"];
var arr=["a(1)","a(6)","a","a","a","a","a","a","a","a","a","a"];
var arr1=new Array();
for (var r in arr)
{
if(arr1.indexOf(arr[r])>-1)
{
var ind=1;
while(arr1.indexOf(arr[r]+'('+ind+')')>-1)
{
ind++;
}
var str=arr[r]+'('+ind+')';
arr1.push(str);
}
else
{
arr1.push(arr[r]);
}
}
document.write("INPUT:"+arr+"</br>");
document.write("OUTPUT:"+arr1);

This was my beginner approach:
const renameFiles = arr => {
const fileObj = {};
let count = 0;
const renamed = arr.map(currentFile => {
if (!Object.keys(fileObj).includes(currentFile)) {
fileObj[currentFile] = count;
return currentFile;
} else {
count++;
if (Object.keys(fileObj).includes(`${currentFile}(${count})`)) {
count++;
return `${currentFile}(${count})`;
} else return `${currentFile}(${count})`;
}
});
return renamed;
};

Here is a working c++ impl.
#include <map>
#include <string>
using namespace std;
string makeName(string n, int i)
{
string ret = n + "(";
ret += std::to_string(i);
ret += ")";
return ret;
}
std::vector<std::string> fileNaming(std::vector<std::string> names)
{
map<string, int> lookup;
vector<string> outNames;
for (auto name : names)
{
auto f = lookup.find(name);
if (f != lookup.end())
{
int index = 1;
while (lookup.find(makeName(name, index)) != lookup.end())
{
index++;
}
name = makeName(name, index); // reassign
}
lookup[name] = 1;
outNames.push_back(name);
}
return outNames;
}

Here is my approach in Javascript:
function fileNaming(names) {
for (i in names) {
if (names.slice(0,i).includes(names[i])) {
j = 1
while (names.slice(0,i).includes(names[i]+"("+j.toString()+")")) {j++}
names[i] += "(" + j.toString() + ")"}}
return names
}

Related

isset equivalent in javascript to find palindrome

I created a script in PHP to find a palindrome, but when I try to do the same in JavaScript, then it is not working as expected. It's not just a matter of checking if the string that is reversed matches, but any order of the string has to be checked as well.
In other words, "mom" should return as true, "mmo" should return as true, "omm" should return as true, etc..., which is what the PHP script does, but the JS script below doesn't even work for the first iteration for the string "mom"
The following is the PHP script:
<?php
function is_palindrom($str) {
$str_array = str_split($str);
$count = array();
foreach ($str_array as $key) {
if(isset($count[$key])) {
$count[$key]++;
} else {
$count[$key] = 1;
}
}
$odd_counter = 0;
foreach ($count as $key => $val) {
if(($val % 2) == 1) {
$odd_counter++;
}
}
return $odd_counter <= 1;
}
echo is_palindrom('mom') ? "true" : "false";
The following is what I have tried in JS:
var count = [];
var strArr = [];
var oddCounter = 0;
var foreach_1 = function(item, index) {
console.log("count[index]: " + count[index]);
if (typeof count[index] !== "undefined") {
count[index]++;
} else {
count[index] = 1;
}
};
var foreach_2 = function(item, index) {
console.log("item: " + item + " item % 2: " + eval(item % 2));
if (eval(item % 2) == 1) {
oddCounter++;
}
console.log("oddCounter: " + oddCounter);
return oddCounter <= 1;
};
var isPalindrom = function(str) {
strArr = str.split("");
console.log(strArr);
strArr.forEach(foreach_1);
console.log(count);
count.forEach(foreach_2);
};
I believe it is failing where I try to replicate isset in javascript, with the following code:
if (typeof count[index] !== "undefined") {
As a result, I have tried to write my own isset function, but still the same result, it is not working:
var isset = function(obj) {
if (typeof obj === "undefined" || obj === null) {
return false;
} else {
return true;
}
};
With the following function being called:
if (isset(count[index])) {
count[index]++;
} else {
count[index] = 1;
}
As usual, any help would be appreciated and thanks in advance
BTW, it's killing me that I cannot remember the word for several revisions or iterations of something - I know that it starts with "re"
My attempt:
let p1 = `No 'x' in Nixon.`
let p2 = `Was it a car or a cat I saw?`
let p3 = `A man, a plan, a canal, Panama!`
function is_palindrome (str) {
const normalize = str => str.replace(/[.,:;`'"!?\/#$%\^&\*{}=\-_~()\s]/g, '').toLowerCase()
const reverse = str => [...str].reverse().join('')
return normalize(str) === reverse(normalize(str))
? true
: false
}
console.log(is_palindrome(p1))
console.log(is_palindrome(p2))
console.log(is_palindrome(p3))
First, thank you for all the comments.
Second, I ran a var_dump on the count array in the PHP file and this was the result:
array (size=2)
'm' => int 2
'o' => int 1
Which lead me to understand that count in js has to be an object for this work and I would have to create indexes of the object, depending on the string entered.
One thing lead to another and a complete re-write, but it works, along with a spell checker - see link at the bottom for complete code:
var count = {};
var strArr = [];
var oddCounter = 0;
var objKeys = [];
var splitString;
var reverseArray;
var joinArray;
var url = "test-spelling.php";
var someRes = "";
var mForN = function(obj, strArr) {
for (var y = 0; y < strArr.length; y++) {
// console.log("obj[strArr[" + y + "]]: " + obj[strArr[y]]);
if (isset(obj[strArr[y]])) {
obj[strArr[y]]++;
} else {
obj[strArr[y]] = 1;
}
}
return obj;
};
var mForN_2 = function(obj, objKeys) {
for (var z = 0; z < objKeys.length; z++) {
/* console.log(
"obj[objKeys[z]]: " +
obj[objKeys[z]] +
" obj[objKeys[z]] % 2: " +
eval(obj[objKeys[z]] % 2)
); */
if (eval(obj[objKeys[z]] % 2) == 1) {
oddCounter++;
}
// console.log("oddCounter: " + oddCounter);
}
return oddCounter <= 1;
};
var isset = function(obj) {
if (typeof obj === "undefined" || obj === null) {
return false;
} else {
return true;
}
};
var isPalindrom = function(str) {
// reverse original string
splitString = str.split("");
reverseArray = splitString.reverse();
joinArray = reverseArray.join("");
var checking = checkSpellingOfStr(str);
if (str == joinArray) {
strArr = str.split("");
// console.log("strArr: " + strArr);
objKeys = makeObjKeys(count, strArr);
// console.log("filled count before mForN: " + JSON.stringify(count));
// create array of keys in the count object
objKeys = Object.keys(count);
// console.log("objKeys: " + objKeys);
count = mForN(count, strArr);
// console.log("count after mForN: " + JSON.stringify(count));
return mForN_2(count, objKeys);
} else {
return 0;
}
};
var makeObjKeys = function(obj, arr) {
for (var x = 0; x < arr.length; x++) {
obj[arr[x]] = null;
}
return obj;
};
var checkSpellingOfStr = function(someStr) {
var formData = {
someWord: someStr
};
$.ajax({
type: "GET",
url: url,
data: formData,
success: function(result) {
if (!$.trim(result)) {
} else {
console.log(result);
$("#checkSpelling").html(result);
}
}
});
};
Start everything with the following call:
isPalindrom("mom") ? demoP.innerHTML = "is pal" : demoP.innerHTML = "is not pal";
In my example, I have a form and I listen for a button click as follows:
var palindromeTxt = document.getElementById("palindromeTxt").value;
var btn = document.getElementById("button");
btn.addEventListener("click", function (event) {
isPalindrom(palindromeTxt) ? demoP.innerHTML = "is pal" : demoP.innerHTML = "is not pal";
});
The following is the php for spell check:
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
if(!empty($_REQUEST['someWord']))
{
$someWord = $_REQUEST['someWord'];
}
$pspell_link = pspell_new("en");
if (pspell_check($pspell_link, $someWord)) {
echo trim($someWord) . " is a recognized word in the English language";
} else {
echo "Your word is either misspelled or that is not a recognized word";
}
You will need pspell installed on your server, as well as adding extension=pspell.so to your php.ini
This is what I did, to get it running locally on my mac:
cd /Users/username/Downloads/php-5.6.2/ext/pspell
/usr/local/bin/phpize
./configure --with-php-config=/usr/local/php5-5.6.2-20141102-094039/bin/php-config --with-pspell=/opt/local/
make
cp ./modules/* /usr/local/php5-5.6.2-20141102-094039/lib/php/extensions/no-debug-non-zts-20131226
sudo apachectl restart
check your phpinfo file and you should see the following:
pspell
PSpell Support enabled
Live example

Javascript , sum of key pair value's

anyone have a solution to add up these key pair values for the one key? I've tried to add them to the key pair value using dict[id] += parseFloat(value) but it results in incorrect operation. I've tried using eval(valuestring), I'm pretty sure the value's inside the key are still a string. Need to get the sum of each ID for a leaderboard.
Any help is much appreciated.
Output of keys of dict_tips
'["U5WUV3A3G"]': '1000.0,200.0,300.0,100.0,500.0,420.0,42.0,98.0,500.0,150.0,300.0,300.0,25.0,200.0,',
'["U5FHMCWP7"]': '50.0,500.0,1000.0,45.0,1000.0,100.0,15.0,3.0,675.0,100.0,225.0,25.0,900.0,100.0,1000.0,10.0,30.0,0.001,0.005,1.755,1.724,1.5,',
'["U5SJQMME3"]': '100000.,100.0,100.0,100.0,50.0,100.0,100.0,40000.0,10.0,200.0,500.0,',
'["U6KAYAJ5Q"]': '100.0,200.0,900.0,100.0,100.0,100.0,1000.0,10.0,10.0,1000.0,100.0,100.0,1.0,10.0,800.0,200.0,100.0,190.0,190.0,10.0,10.0,',
'["U6F1AHQ8H"]': '10.0,100.0,',
'["U3H65TS9K"]': '500.0,100.0,200.0,500.0,35.414,12.345,',
'["U5HUZG3MF"]': '1.0,0.5,42.0,44.0,1.0,1.0,7.995,100.0,100.0,100.0,50.0,100.0,4.0,5.0,5.0,5.0,5.0,5.0,',
'["U5ZPTLXV5"]': '5.0,',
'["U6EMQC2LF"]': '737.998,2000.0,1000.0,300.0,666.0,6000.0,5000.0,5000.0,1000.0,5000.0,999.0,1.0,5000.0,3000.0,5000.0,9999.0,',
'["U62EVB2P7"]': '50.0,20.0,100.0,1.0,100.0,50.0,100.0,50.0,100.0,100.0,1.0,',
'["U3GJ9SREZ"]': '150.0,100.0,100.0,100.0,',
'["U6F0KBT2P"]': '1000.0,100.0,1000.0,100.0,800.0,100.0,100.0,',
'["U5WD17D5E"]': '150.0,75.0,',
'["U697Y6BL3"]': '5.0,1.0,51.0,2.0,1.0,1.0,5.0,',
'["U6GU038HX"]': '4000.0,',
'["U4B0NK2NR"]': '100.0,500.0,200.0,100.0,100.0,100.0,100.0,',
'["U6C23F8MT"]': '49.0,100.0,',
'["U5KQY01ST"]': '105.0,',
'["U6FSC0CC8"]': '100.0,100.0,',
'["U659939GF"]': '20.0,100.0,100.0,100.0,',
'["U5URNPRSA"]': '5.0,20.0,5.0,5.0,50.0,',
'["U5VAMV76F"]': '0.5,20.0,200.0,200.0,200.0,200.0,100.0,200.0,5.0,500.0,200.0,50.0,',
'["U5UL7KWKU"]': '150.0,200.0,',
'["U61NYHM25"]': '64.0,2.0,',
'["U6CMX965S"]': '10.0,10.0,20.0,50.0,30.0,',
'["U5G40R5PF"]': '499.0,',
'["U4XHS3DHA"]': '51.0,',
'["U69MY9WDS"]': '10.0,6.414,10.0,10.0,',
'["U666S65RC"]': '100.0,100.0,',
'["U5X3MEZ39"]': '1.0,1.0,10.01,10.1,0.002,0.01,1.1,' ]
Core
var dict_tips = [];
var dict_counts = [];
var sum = []
for (var i = 0; i < 200 ; i++) {
var str = res.messages.matches[i].text;
var stdout = capcon.captureStdout(function scope() {
for (var x = 46 ; x < 55 ; x++) {
process.stdout.write(str[x]);
}
});
var id = JSON.stringify(stdout.match(/.{1,9}/g))
var stdout = capcon.captureStdout(function scope() {
for (var x = 76 ; x < 85 ; x++) {
process.stdout.write(str[x]);
} });
var extract = JSON.stringify(stdout.match(/.{1,9}/g));
var parse = extract.indexOf(/.RDD|RD|R|D|:| /g)
var x = checkAndAdd(id,extract)
function checkAndAdd(id,extract) {
var found = dict_tips.some(function (el) {
return el.key === id; })
if (!found) { if (parse = -1)
{
var format = ( ""+extract.slice(2,9)).replace(/.RDD|RD|R|D|:| /g,'');
var x = format.substr(0, 9) + " " + format.substr(9);
var total = x.split(" ")
dict_tips.push({key: id})
dict_tips[id] += total
}
else
{
var format = extract.slice(2,9)
var x = format.substr(0, 9) + " " + format.substr(9)
var total = x.split(" ")
dict_tips.push({key: id})
dict_tips[id] = "";
dict_tips[id] += total
}
}
else
{
var extract = stdout.match(/.{1,9}/g);
var parse = extract.indexOf(/.RDD|RD|R|D|:| /g)
if (parse = -1)
{
var format = ( "" + extract).replace(/.RDD|RD|R|D|:| /g,'');
var x = format.substr(0, 9) + " " + format.substr(9);
var total = x.split(" ")
dict_tips[id] += total
}
else
{
var format = extract.slice(1,9)
var x = format.substr(0, 9) + " " + format.substr(9);
var total = x.split(" ")
dict_tips[id] += total
};
}
}
}
var sum = dict_tips.reduce(function(a, b) { return a + b; }, 0);
console.log(JSON.stringify(sum))
console.log(dict_tips)
Split the string, then parseFloat and sum up the values:
const data = {
'["U5WUV3A3G"]': '1000.0,200.0,300.0,100.0,500.0,420.0,42.0,98.0,500.0,150.0,300.0,300.0,25.0,200.0,',
'["U5FHMCWP7"]': '50.0,500.0,1000.0,45.0,1000.0,100.0,15.0,3.0,675.0,100.0,225.0,25.0,900.0,100.0,1000.0,10.0,30.0,0.001,0.005,1.755,1.724,1.5,',
'["U5SJQMME3"]': '100000.,100.0,100.0,100.0,50.0,100.0,100.0,40000.0,10.0,200.0,500.0,',
'["U6KAYAJ5Q"]': '100.0,200.0,900.0,100.0,100.0,100.0,1000.0,10.0,10.0,1000.0,100.0,100.0,1.0,10.0,800.0,200.0,100.0,190.0,190.0,10.0,10.0,',
'["U6F1AHQ8H"]': '10.0,100.0,',
'["U3H65TS9K"]': '500.0,100.0,200.0,500.0,35.414,12.345,',
'["U5HUZG3MF"]': '1.0,0.5,42.0,44.0,1.0,1.0,7.995,100.0,100.0,100.0,50.0,100.0,4.0,5.0,5.0,5.0,5.0,5.0,',
'["U5ZPTLXV5"]': '5.0,',
'["U6EMQC2LF"]': '737.998,2000.0,1000.0,300.0,666.0,6000.0,5000.0,5000.0,1000.0,5000.0,999.0,1.0,5000.0,3000.0,5000.0,9999.0,',
'["U62EVB2P7"]': '50.0,20.0,100.0,1.0,100.0,50.0,100.0,50.0,100.0,100.0,1.0,',
'["U3GJ9SREZ"]': '150.0,100.0,100.0,100.0,',
'["U6F0KBT2P"]': '1000.0,100.0,1000.0,100.0,800.0,100.0,100.0,',
'["U5WD17D5E"]': '150.0,75.0,',
'["U697Y6BL3"]': '5.0,1.0,51.0,2.0,1.0,1.0,5.0,',
'["U6GU038HX"]': '4000.0,',
'["U4B0NK2NR"]': '100.0,500.0,200.0,100.0,100.0,100.0,100.0,',
'["U6C23F8MT"]': '49.0,100.0,',
'["U5KQY01ST"]': '105.0,',
'["U6FSC0CC8"]': '100.0,100.0,',
'["U659939GF"]': '20.0,100.0,100.0,100.0,',
'["U5URNPRSA"]': '5.0,20.0,5.0,5.0,50.0,',
'["U5VAMV76F"]': '0.5,20.0,200.0,200.0,200.0,200.0,100.0,200.0,5.0,500.0,200.0,50.0,',
'["U5UL7KWKU"]': '150.0,200.0,',
'["U61NYHM25"]': '64.0,2.0,',
'["U6CMX965S"]': '10.0,10.0,20.0,50.0,30.0,',
'["U5G40R5PF"]': '499.0,',
'["U4XHS3DHA"]': '51.0,',
'["U69MY9WDS"]': '10.0,6.414,10.0,10.0,',
'["U666S65RC"]': '100.0,100.0,',
'["U5X3MEZ39"]': '1.0,1.0,10.01,10.1,0.002,0.01,1.1,'
}
const sums = Object.keys(data).reduce((results, key) => {
results[key] = data[key].split(',')
.map(item => parseFloat(item))
.filter(item => !isNaN(item))
.reduce((res, item) => res + item, 0)
return results
}, {})
console.log(sums)
In PHP, you would do an explode on the commas, think for javascript its split. After you would run a loop through each index of the array that the split function just created and adding to a total sum. You would need to do a parsefloat on each value of the index as well.
You can simply iterate through the keys of the data using for in.
Then you need to split the string into an array, and sum up the values using reduce.
const data = {
'["U5WUV3A3G"]': '1000.0,200.0,300.0,100.0,500.0,420.0,42.0,98.0,500.0,150.0,300.0,300.0,25.0,200.0,',
'["U5FHMCWP7"]': '50.0,500.0,1000.0,45.0,1000.0,100.0,15.0,3.0,675.0,100.0,225.0,25.0,900.0,100.0,1000.0,10.0,30.0,0.001,0.005,1.755,1.724,1.5,',
'["U5SJQMME3"]': '100000.,100.0,100.0,100.0,50.0,100.0,100.0,40000.0,10.0,200.0,500.0,',
'["U6KAYAJ5Q"]': '100.0,200.0,900.0,100.0,100.0,100.0,1000.0,10.0,10.0,1000.0,100.0,100.0,1.0,10.0,800.0,200.0,100.0,190.0,190.0,10.0,10.0,',
'["U6F1AHQ8H"]': '10.0,100.0,',
'["U3H65TS9K"]': '500.0,100.0,200.0,500.0,35.414,12.345,',
'["U5HUZG3MF"]': '1.0,0.5,42.0,44.0,1.0,1.0,7.995,100.0,100.0,100.0,50.0,100.0,4.0,5.0,5.0,5.0,5.0,5.0,',
'["U5ZPTLXV5"]': '5.0,',
'["U6EMQC2LF"]': '737.998,2000.0,1000.0,300.0,666.0,6000.0,5000.0,5000.0,1000.0,5000.0,999.0,1.0,5000.0,3000.0,5000.0,9999.0,',
'["U62EVB2P7"]': '50.0,20.0,100.0,1.0,100.0,50.0,100.0,50.0,100.0,100.0,1.0,',
'["U3GJ9SREZ"]': '150.0,100.0,100.0,100.0,',
'["U6F0KBT2P"]': '1000.0,100.0,1000.0,100.0,800.0,100.0,100.0,',
'["U5WD17D5E"]': '150.0,75.0,',
'["U697Y6BL3"]': '5.0,1.0,51.0,2.0,1.0,1.0,5.0,',
'["U6GU038HX"]': '4000.0,',
'["U4B0NK2NR"]': '100.0,500.0,200.0,100.0,100.0,100.0,100.0,',
'["U6C23F8MT"]': '49.0,100.0,',
'["U5KQY01ST"]': '105.0,',
'["U6FSC0CC8"]': '100.0,100.0,',
'["U659939GF"]': '20.0,100.0,100.0,100.0,',
'["U5URNPRSA"]': '5.0,20.0,5.0,5.0,50.0,',
'["U5VAMV76F"]': '0.5,20.0,200.0,200.0,200.0,200.0,100.0,200.0,5.0,500.0,200.0,50.0,',
'["U5UL7KWKU"]': '150.0,200.0,',
'["U61NYHM25"]': '64.0,2.0,',
'["U6CMX965S"]': '10.0,10.0,20.0,50.0,30.0,',
'["U5G40R5PF"]': '499.0,',
'["U4XHS3DHA"]': '51.0,',
'["U69MY9WDS"]': '10.0,6.414,10.0,10.0,',
'["U666S65RC"]': '100.0,100.0,',
'["U5X3MEZ39"]': '1.0,1.0,10.01,10.1,0.002,0.01,1.1,'
}
let sum = {};
for (var key in data) {
let arr = data[key].split(',');
let total = arr.reduce((acc, curr) => {
if (parseInt(curr)) {
return acc + parseInt(curr);
}
return acc;
}, 0);
sum[key] = total;
}
console.log(sum)

Expansion of algebraic term

I am trying to expand an algebraic term.
(x+1)(x+1)/x => x + 2 + x^-1
(x+1)^3 => x^3 + 3x^2 + 3x + 1
(x^2*x)(x^2) => x^5
This is my attempt at it. I have tried a lot of ways trying to fix the problems below.
Problems:
Like terms should be added together
(x+1)(x+1)(x+1) should be valid.
(x+1)^2 should be equal to (x+1)(x+1)
x(x+1) should be valid
1x^n should just be x^n
There should be no 0x^n terms.
nx^0 terms should just be n
Code Snippet:
function split(input) {
return ((((input.split(")(")).toString()).replace(/\)/g, "")).replace(/\(/g, "")).split(','); }
function strVali(str) {
str = str.replace(/\s+/g, "");
var parts = str.match(/[+\-]?[^+\-]+/g);
// accumulate the results
return parts.reduce(function(res, part) {
var coef = parseFloat(part) || +(part[0] + "1") || 1;
var x = part.indexOf('x');
var power = x === -1 ?
0:
part[x + 1] === "^" ?
+part.slice(x + 2) :
1;
res[power] = (res[power] || 0) + coef;
return res;
}, {});
}
function getCoeff(coeff) {
var powers = Object.keys(strVali(coeff));
var max = Math.max.apply(null, powers);
var result = [];
for(var i = max; i >= 0; i--)
result.push(strVali(coeff)[i] || 0);
return result; }
function evaluate(expression) {
var term1 = getCoeff(expression[0]);
var term2 = getCoeff(expression[1]);
var expand = "";
for ( var j = 0; j < term1.length; j++ ) {
for ( var i = 0; i < term2.length; i++ ) {
expand += Number(term1[j] * term2[i]) + 'x^ ' + (Number(term1.length) - 1 - j + Number(term2.length) - 1 - i) + ' + ';
}}
var final = "";
for ( var Z = 0; Z < getCoeff(expand).length; Z++) {
final += ' ' + getCoeff(expand)[Z] + 'x^ {' + (getCoeff(expand).length - Z - 1) + '} +';
}
final = "$$" + ((((((final.replace(/\+[^\d]0x\^ \{[\d]+\}/g,'')).replace(/x\^ \{0}/g,'')).replace(/x\^ \{1}/g,'x')).replace(/[^\d]1x\^ /g,'+ x^')).replace(/\+ -/g,' - ')).slice(0, -1)).substring(1,(final.length)) + "$$";
document.getElementById('result').innerHTML = final;
MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById('result')]);
}
function caller() {
var input = document.getElementById('input').value;
evaluate(split(input)); }
div.wrapper {
width: 100%;
height:100%;
border:0px solid black;
}
input[type="text"] {
display: block;
margin : 0 auto;
padding: 10px;
font-size:20px;
}
button{
margin:auto;
display:block;
background-color: white;
color: black;
border: 2px solid #555555;
padding-left: 20px;
padding-right: 20px;
font-size: 20px;
margin-top:10px;
}
button:hover {
box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24),0 17px 50px 0 rgba(0,0,0,0.19);
}
<script type="text/javascript" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML">
</script>
<div class='wrapper'><input id="input" title="Enter Expression" type="text" value="(x^2+x+1)(x^2+x+1)"></div>
<div> <button onclick="caller()">Click</button></div>
<div id="result">$$x^4 + 2x^3 + 3x^2 + 2x + 1$$</div>
Reference:
How to calculate coefficients of polynomial expansion in javascript
Getting coefficients of algebraic term
How to get a term before a character?
Edit: I have re-written my original answer from when the question did not include the - and / operators). My new answer supports - and /.
Since you have not defined a precise grammar, I have made some assumptions. I support the +, -, /, ^ operators and the implicit multiply. These can operate on numbers, x and (...) expressions, except that right hand side of the ^ operator must be a number. I allow spaces between tokens.
Limitations: The -is a binary not unary - operator, So x-2 if OK, -2 on its own is a syntax error. The / is limited. You may divide by a value with a single coefficient such as 2, 'x', 2x^2, but not by cannot have 1/(x^2+1), which would evaluate to an infinite series.
It first takes the string and wraps it in a 'tokenizer' which lets you look it one token at a time, where a token is a number, x, ( ) or operator.
It then calls evaluateSum() which evaluates things separated by + or -, where each thing is a product evaluated by evaluateProduct(). This in turn uses evaluatePower() to evalue the ^. Finally evaluateTerm() looks for x, numbers and bracketed sub-expressions which are evaluates recursively with evaluateSum(). This hierarchy creates the correct operator precedence and evaluation order.
Each layer of the evaluation returns a 'coefficients' object which s array-like, but may contain megative indexes. For example [1,0,1] means 1+x^2.
It can cope with any number of nested brackets and a lot of other case such as xx(x) is x^3, 2^3 is 8. I have added a few throws for syntax errors, for example 2^x is illegal.
function makeTokenizer(source) {
var c, i, tokenizer;
i = 0; // The index of the current character.
c = source.charAt(i); // The current character.
function consumeChar() { // Move to next c, return previous c.
var prevC = c;
i += 1;
c = source.charAt(i);
return prevC;
}
tokenizer = {
next : function () {
var str;
while (c === ' ') { // Skip spaces
consumeChar();
}
if (!c) {
tokenizer.token = undefined; // End of source
} else if (c >= '0' && c <= '9') { // number
str = consumeChar(); // First digit
while (c >= '0' && c <= '9') { // Look for more digits.
str += consumeChar();
}
tokenizer.token = Number(str);
} else if (c === "x") {
tokenizer.token = consumeChar();
} else { // single-character operator
tokenizer.token = consumeChar();
}
}
};
tokenizer.next(); // Load first token.
return tokenizer;
}
function makeCoefficients() { // Make like an array but can have -ve indexes
var min = 0, max = 0, c = {};
return {
get: function (i) {
return c[i] || 0;
},
set: function (i, value) {
c[i] = value;
min = Math.min(i, min);
max = Math.max(i + 1, max);
return this; // for chaining
},
forEach: function (callback) {
var i;
for (i = min; i < max; i += 1) {
if (this.get(i)) {
callback(this.get(i), i);
}
}
},
toString: function () {
var result = "", first = true;
this.forEach(function (val, power) {
result += (val < 0 || first) ? "" : "+";
first = false;
result += (val === 1 && power !== 0) ? "" : val;
if (power) {
result += "x";
if (power !== 1) {
result += "^" + power;
}
}
});
return result;
},
toPowerOf: function (power) {
if (power === 0) {
return makeCoefficients().set(0, 1); // Anything ^0 = 1
}
if (power === 1) {
return this;
}
if (power < 0) {
throw "cannot raise to negative powers";
}
return this.multiply(this.toPowerOf(power - 1));
},
multiply: function (coefficients) {
var result = makeCoefficients();
this.forEach(function (a, i) {
coefficients.forEach(function (b, j) {
result.set(i + j, result.get(i + j) + a * b);
});
});
return result;
},
divide: function (coefficients) {
// Division is hard, for example we cannot do infinite series like:
// 1/(1 + x^2) = sum_(n=0 to infinity) 1/2 x^n ((-i)^n + i^n)
// So we do a few easy cases only.
var that = this, result = makeCoefficients(), done;
coefficients.forEach(function (value, pow) {
that.forEach(function (value2, pow2) {
result.set(pow2 - pow, value2 / value);
});
if (done) {
throw "cannot divide by " + coefficients.toString();
}
done = true;
});
return result;
},
add: function (coefficients, op) {
var result = makeCoefficients();
this.forEach(function (value, i) {
result.set(value, i);
});
op = (op === "-" ? -1 : 1);
coefficients.forEach(function (value, i) {
result.set(i, result.get(i) + value * op);
});
return result;
}
};
}
var evaluateSum; // Called recursively
function evaluateTerm(tokenizer) {
var result;
if (tokenizer.token === "(") {
tokenizer.next();
result = evaluateSum(tokenizer);
if (tokenizer.token !== ")") {
throw ") missing";
}
tokenizer.next();
} else if (typeof tokenizer.token === "number") {
result = makeCoefficients().set(0, tokenizer.token);
tokenizer.next();
} else if (tokenizer.token === "x") {
tokenizer.next();
result = makeCoefficients().set(1, 1); // x^1
} else {
return false; // Not a 'term'
}
return result;
}
function evaluatePower(tokenizer) {
var result;
result = evaluateTerm(tokenizer);
if (tokenizer.token === "^") {
tokenizer.next();
if (typeof tokenizer.token !== "number") {
throw "number expected after ^";
}
result = result.toPowerOf(tokenizer.token);
tokenizer.next();
}
return result;
}
function evaluateProduct(tokenizer) {
var result, term, divOp;
result = evaluatePower(tokenizer);
if (!result) {
throw "Term not found";
}
while (true) {
divOp = (tokenizer.token === "/");
if (divOp) {
tokenizer.next();
term = evaluatePower(tokenizer);
result = result.divide(term);
} else {
term = evaluatePower(tokenizer);
if (!term) {
break;
}
result = result.multiply(term);
}
}
return result;
}
function evaluateSum(tokenizer) {
var result, op;
result = evaluateProduct(tokenizer);
while (tokenizer.token === "+" || tokenizer.token === "-") {
op = tokenizer.token;
tokenizer.next();
result = result.add(evaluateProduct(tokenizer), op);
}
return result;
}
function evaluate(source) {
var tokenizer = makeTokenizer(source),
coefficients = evaluateSum(tokenizer);
if (tokenizer.token) {
throw "Unexpected token " + tokenizer.token;
}
console.log(source + " => " + coefficients.toString());
}
// Examples:
evaluate("(x+1)(x+1)"); // => 1+2x+x^2
evaluate("(x+1)^2"); // => 1+2x+x^2
evaluate("(x+1)(x+1)(x+1)"); // => 1+3x+3x^2+x^3
evaluate("(x+1)^3"); // => 1+3x+3x^2+x^3
evaluate("(x)(x+1)"); // => x+x^2
evaluate("(x+1)(x)"); // => x+x^2
evaluate("3x^0"); // => 3
evaluate("2^3"); // => 8
evaluate("(x+2x(x+2(x+1)x))"); // => x+6x^2+4x^3
evaluate("(x+1)(x-1)"); // => -1+x^2
evaluate("(x+1)(x+1)/x"); // x^-1+2+x
//evaluate("(x+1)/(x^2 + 1)"); //throws cannot divide by 1+2x
It can handle +, -, / and implicit multiplication. It expands the parenthesis accordingly and adds them to the original expression while removing the parenthesised version. It collects like terms accordingly. Limitations: It cannot divide by a polynomial and it does not support the * operator.
function strVali(str) {
str = str.replace(/\s+/g, "");
var parts = str.match(/[+\-]?[^+\-]+/g);
return parts.reduce(function(res, part) {
var coef = parseFloat(part) || +(part[0] + "1") || 1;
var x = part.indexOf('x');
var power = x === -1 ?
0:
part[x + 1] === "^" ?
+part.slice(x + 2) :
1;
res[power] = (res[power] || 0) + coef;
return res;
}, {});
}
function getCoeff(coeff) {
var powers = Object.keys(strVali(coeff));
var max = Math.max.apply(null, powers);
var result = [];
for(var i = max; i >= 0; i--)
result.push(strVali(coeff)[i] || 0);
return result; }
function format(str) {
str = ' ' + str;
str = str.replace(/-/g,'+-').replace(/x(?!\^)/g,'x^1').replace(/([+\/*)(])(\d+)([+\/*)(])/g,'$1$2x^0$3').replace(/([^\d])(x\^-?\d+)/g,'$11$2').replace(/(-?\d+x\^\d+)(?=\()/g,'($1)').replace(/(\))(-?\d+x\^\d+)/g,'$1($2)').replace(/([^\)\/])(\()([^\*\/\(\)]+?)(\))(?![(^\/])/g,'$1$3');
str = str.replace(/(\([^\(\)]+?\))\/(\d+x\^-?\d+)/g,'$1/($2)').replace(/(\d+x\^-?\d+)\/(\d+x\^-?\d+)/g,'($1)/($2)').replace(/(\d+x\^-?\d+)\/(\(\d+x\^-?\d+\))/g,'($1)/$2');
return str;
}
function expBrackets(str) {
var repeats = str.match(/\([^\(\)]+?\)\^\d+/g);
if ( repeats === null ) { return str; } else { var totalRepeat = '';
for ( var t = 0; t < repeats.length; t++ ) { var repeat = repeats[t].match(/\d+$/); for ( var u = 0; u < Number(repeat); u++ ) { totalRepeat += repeats[t].replace(/\^\d+$/,''); }
str = str.replace(/\([^\(\)]+?\)\^\d+/, totalRepeat); totalRepeat = ''; }
return str; }
}
function multiply(str) {
var pairs = str.match(/\([^\(\)]+?\)\([^\(\)]+?\)/g);
if ( pairs !== null ) { while ( pairs !== null ) { var output = '';
for (var i = 0; i < pairs.length; i++) { var pair = pairs[i].slice(1).slice(0, -1).split(')('); var firstCoeff = getCoeff(pair[0]); var secondCoeff = getCoeff(pair[1]);
for (var j = 0; j < firstCoeff.length; j++) {
for (var k = 0; k < secondCoeff.length; k++) { output += firstCoeff[j] * secondCoeff[k] + 'x^' + Number(firstCoeff.length - 1 - j + secondCoeff.length - 1 - k) + '+'; } }
var regexp = new RegExp(pairs[i].replace(/\(/g,'\\(').replace(/\+/g,'\\+').replace(/\)/g,'\\)').replace(/\^/g,'\\^').replace(/\-/g,'\\-'));
str = str.replace(regexp, '(' + (output.slice(0, -1).replace(/[^\d]0x\^\d+/g,'')) + ')');
output = ''; }
pairs = str.match(/\([^\(\)]+?\)\([^\(\)]+?\)/g); } }
else { }
str = str.replace(/\+/g,' + ');
return str;
}
function divide(str) {
if ( str.match(/\/(\(-?\d+x\^-?\d+.+?\))/g) === null && str.match(/\//g) !== null ) {
while ( pairs !== null ) {
var pairs = str.match(/\([^\(\)]+?\)\/\([^\(\)]+?\)/g);
var output = '';
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].slice(1).slice(0, -1).split(')/(');
var firstCoeff = getCoeff(pair[0]);
var secondCoeff = getCoeff(pair[1]);
for (var j = 0; j < firstCoeff.length; j++) {
for (var k = 0; k < secondCoeff.length; k++) {
output += firstCoeff[j] / secondCoeff[k] + 'x^' + Number(firstCoeff.length - 1 - j - secondCoeff.length + 1 + k) + '+';
output = output.replace(/([+-])Infinityx\^\-?\d+/g,'').replace(/([+-])NaNx\^\-?\d+/g,'');
} }
var regexp = new RegExp(pairs[i].replace(/\(/g,'\\(').replace(/\+/g,'\\+').replace(/\)/g,'\\)').replace(/\^/g,'\\^').replace(/\-/g,'\\-'));
str = str.replace(regexp, '(' + (output.slice(0, -1).replace(/[^\d]0x\^-?\d+/g,'')) + ')');
output = ''; }
pairs = str.match(/\([^\(\)]+?\)\/\([^\(\)]+?\)/g); } }
else { }
return str;
}
function evaluate(str) {
var result = format(divide(format(multiply(expBrackets(format((str)))))));
var resultCollect = '';
result = result.replace(/\s+/g, "").replace(/[^\d]0x\^-?\d+/g,'').replace(/\+/g,' + ');
if ( result === '') {
document.getElementById('result').innerHTML = '$$' + str + '$$' + '$$ = 0 $$';
MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById('result')]);
} else if ( result.match(/-?\d+x\^-\d+/g) === null && str.match(/\/(\(-?\d+x\^-?\d+.+?\))/g) === null) {
for ( var i = 0; i < getCoeff(result).length; i++ ) {
resultCollect += getCoeff(result)[i] + 'x^' + Number(getCoeff(result).length - 1 - i) + '+' ; }
if ( resultCollect !== '')
resultCollect = '$$ = ' + resultCollect.slice(0,-1).replace(/[^\d]0x\^-?\d+/g,'').replace(/\+/g,' + ').replace(/x\^0/g,'').replace(/x\^1(?!\d+)/g,'x').replace(/\^(-?\d+)/g,'\^\{$1\}').replace(/\+ -/g,' - ') + '$$';
else
resultCollect = 'Error: Trying to divide by a polynomial ';
document.getElementById('result').innerHTML = '$$' + str.replace(/\^(-?\d+)/g,'\^\{$1\}') + '$$' + resultCollect;
MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById('result')]);
} else {
resultCollect = '$$ = ' + result.replace(/\^(-?\d+)/g,'\^\{$1\}') + '$$';
document.getElementById('result').innerHTML = '$$' + str.replace(/\^(-?\d+)/g,'\^\{$1\}').replace(/\+ -/g,' - ') + '$$' + resultCollect;
MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById('result')]);
}
}
function caller() {
var input = document.getElementById('input').value;
evaluate(input);
}
div.wrapper {
width: 100%;
height:100%;
border:0 solid black;
}
input[type="text"] {
display: block;
margin : 0 auto;
padding: 10px;
font-size:20px;
}
button{
margin:auto;
display:block;
background-color: white;
color: black;
border: 2px solid #555555;
padding-left: 20px;
padding-right: 20px;
font-size: 20px;
margin-top:10px;
}
button:hover {
box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24),0 17px 50px 0 rgba(0,0,0,0.19);
}
<script type="text/javascript" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML">
</script>
<input id="input" type="text" title="Enter Expression: ">
<button onclick="caller()">Click</button>
<div id="result"></div>
<div id="errors"></div>
My approach utilizes two helper classes:
-Term: This stores a coefficient and an object, the keys of which are variables and the values of which are the exponents. It has methods for determining whether terms are the "same" (i.e. whether they have the same variables with the same exponents, thus allowing them to be added), adding terms, and multiplying terms.
-Polynomial: This stores an array of terms. It has methods for adding two polynomials, multiplying two polynomials, and simplifying polynomials (eliminating terms with 0 coefficients and combining like terms).
It has two substantial helper functions:
-findOuterParens - Given a string, this function returns the indices of the first outermost pair of left and right parentheses.
-parseExpressionStr - This function uses a regular expression to split a string into three types of substrings: 1) a number, 2) a symbol (i.e. a variable, like 'x' or 'y'), or 3) an operator (*, -, +, ^, /). It creates Polynomial objects for the first two types and leaves the operators as strings.
The expand function runs the show. It takes in a string and returns a Polynomial object representing the expanded form of the polynomial in the string. It does this as follows:
1) It deals with parentheses by recursion. It uses findOuterParens to find all outermost parenthsized substrings. So for "3x*(x+4)+(2(y+1))*t", for instance, it would find "x+4" and "2(y+1)" as parenthsized substrings. It then passes these to itself for further parsing. For "2(y+1)", it would identify "y+1" as a parenthesized substring, and pass this to itself, for three levels of recursion for this example.
2) It deals with other parts of the string using parseExpressionStr. After steps 1 and 2, it has an array containing Polynomial objects and operators (stored as strings). It then proceeds to simplifying and expanding.
3) It converts subtraction subproblems to addition subproblems by replacing all -'s with +'s and multiplying all polynomials following -'s by -1.
4) It converts division subproblems to multiplication subproblems by replacing /'s with *'s and inverting the Polynomial following the /. If the polynomial following the / has more than one term, it throws an error.
5) It converts power subproblems to multiplication subproblems by replacing ^'s with a series of multiplications.
6) It adds in implicit *'s. I.e. if two Polynomial elements are right next to each other in the array, then it's inferred that they are being multiplied, so, e.g. '2*x' == '2x'.
7) Now the array has polynomial objects alternating with either '+' or '*'. It first performs all polynomial multiplications and then performs all additions.
8) It performs a final simplification step and returns the resulting expanded polynomial.
<html>
<head></head>
<body></body>
<script>
function findOuterParens(str) {
var leftIndex = str.indexOf('('), leftNum = 1, rightNum = 0;
if (leftIndex === -1)
return
for (var i=leftIndex+1; i<str.length; i++) {
if (str[i] === '(')
leftNum++;
else if (str[i] === ')')
rightNum++, rightIndex=i;
if (leftNum === rightNum)
return {start: leftIndex, end: rightIndex}
}
throw Error('Parenthesis at position ' + leftIndex + ' of "' + str + '" is unpaired.');
}
function parseExpressionStr(inputString) {
var result = [], str = inputString;
while (str) {
var nextPart = str.match(/([\d]+)|([\+\-\^\*\/])|([a-zA-z])/);
if (!nextPart)
return result;
if (nextPart.length === 0)
throw Error('Unable to parse expression string "' + inputString + '". Remainder "' + str + '" could not be parsed.');
else if (nextPart[1]) // First group (digits) matched
result.push(new Polynomial(parseFloat(nextPart[0])));
else if (nextPart[3]) // Third group (symbol) matched
result.push(new Polynomial(nextPart[0]));
else // Second group (operator) matched
result.push(nextPart[0]);
str = str.substring(nextPart.index+nextPart[0].length);
}
return result
}
function isOperator(char) {
return char === '*' || char === '/' || char === '^' || char === '+' || char === '-';
}
function Polynomial(value) {
this.terms = (value!==undefined) ? [new Term(value)] : [];
}
Polynomial.prototype.simplify = function() {
for (var i=0; i<this.terms.length-1; i++) {
if (this.terms[i].coeff === 0) {
this.terms.splice(i--, 1);
continue;
}
for (var j=i+1; j<this.terms.length; j++) {
if (Term.same(this.terms[i], this.terms[j])) {
this.terms[i] = Term.add(this.terms[i], this.terms[j]);
this.terms.splice(j--, 1);
}
}
}
}
Polynomial.add = function(a, b) {
var result = new Polynomial();
result.terms = a.terms.concat(b.terms);
result.simplify();
return result
}
Polynomial.multiply = function(a, b) {
var result = new Polynomial();
a.terms.forEach(function(aTerm) {
b.terms.forEach(function (bTerm) {
result.terms.push(Term.multiply(aTerm, bTerm));
});
});
result.simplify();
return result
}
Polynomial.prototype.toHtml = function() {
var html = ''
for (var i=0; i<this.terms.length; i++) {
var term = this.terms[i];
if (i !== 0)
html += (term.coeff < 0) ? ' - ' : ' + ';
else
html += (term.coeff < 0) ? '-' : '';
var coeff = Math.abs(term.coeff);
html += (coeff === 1 && Object.keys(term.symbols).length > 0) ? '' : coeff;
for (var symbol in term.symbols) {
var exp = term.symbols[symbol];
exp = (exp !== 1) ? exp : '';
html += symbol + '<sup>' + exp + '</sup>';
}
}
return html;
}
function Term(value) {
this.symbols = {};
if (typeof value==='string') { // Symbol
this.symbols[value] = 1;
this.coeff = 1;
} else if (typeof value==='number') { // Number
this.coeff = value;
} else {
this.coeff = 1;
}
}
Term.same = function(a, b) {
if (Object.keys(a.symbols).length != Object.keys(b.symbols).length)
return false
else
for (var aSymbol in a.symbols)
if (a.symbols[aSymbol] != b.symbols[aSymbol]) return false
return true
}
Term.add = function(a, b) {
var result = new Term();
Object.assign(result.symbols, a.symbols);
result.coeff = a.coeff + b.coeff;
return result
}
Term.multiply = function(a, b) {
var result = new Term();
Object.assign(result.symbols, a.symbols);
for (var symbol in b.symbols) {
if (!(symbol in result.symbols))
result.symbols[symbol] = 0;
result.symbols[symbol] += b.symbols[symbol];
if (result.symbols[symbol] === 0)
delete result.symbols[symbol];
}
result.coeff = a.coeff * b.coeff;
return result
}
function expand(str) {
var result = [];
var parens = findOuterParens(str);
while (parens) {
result = result.concat(parseExpressionStr(str.slice(0,parens.start)));
result.push(expand(str.slice(parens.start+1, parens.end)))
str = str.slice(parens.end+1);
parens = findOuterParens(str);
}
result = result.concat(parseExpressionStr(str));
// Move -s to coefficients
var minus = result.indexOf('-'), minusPoly = new Polynomial(-1);
while (minus !== -1) {
result[minus] = '+';
result[minus+1] = Polynomial.multiply(minusPoly, result[minus+1]);
minus = result.indexOf('-');
}
// Get rid of +s that follow another operator
var plus = result.indexOf('+');
while (plus !== -1) {
if (plus===0 || isOperator(result[plus-1])) {
result.splice(plus--, 1);
}
plus = result.indexOf('+', plus+1);
}
// Convert /s to *s
var divide = result.indexOf('/');
while (divide !== -1) {
result[divide] = '*';
var termsToInvert = result[divide+1].terms;
if (termsToInvert.length > 1)
throw Error('Attempt to divide by a polynomial with more than one term.');
var termToInvert = termsToInvert[0];
for (var symbol in termToInvert.symbols) {
termToInvert.symbols[symbol] = -termToInvert.symbols[symbol];
}
termToInvert.coeff = 1/termToInvert.coeff;
divide = result.indexOf('/');
}
// Convert ^s to *s
var power = result.indexOf('^');
while (power !== -1) {
var exp = result[power+1];
if (exp.terms.length > 1 || Object.keys(exp.terms[0].symbols).length != 0)
throw Error('Attempt to use non-number as an exponent');
exp = exp.terms[0].coeff;
var base = result[power-1];
var expanded = [power-1, 3, base];
for (var i=0; i<exp-1; i++) {
expanded.push('*');
expanded.push(base);
}
result.splice.apply(result, expanded);
power = result.indexOf('^');
}
// Add implicit *s
for (var i=0; i<result.length-1; i++)
if (!isOperator(result[i]) && !(isOperator(result[i+1])))
result.splice(i+1, 0, '*');
// Multiply
var mult = result.indexOf('*');
while (mult !== -1) {
var product = Polynomial.multiply(result[mult-1], result[mult+1]);
result.splice(mult-1, 3, product);
mult = result.indexOf('*');
}
// Add
var add = result.indexOf('+');
while (add !== -1) {
var sum = Polynomial.add(result[add-1], result[add+1]);
result.splice(add-1, 3, sum);
add = result.indexOf('+');
}
result[0].simplify();
return result[0];
}
var problems = ['(x+1)(x+1)/x', '(x+1)^3', '(x^2*x)(x^2)', '(x+1)(x+1)(x+1)',
'(x+1)^2', 'x(x+1)', '1x^4', '(x + (x+2))(x+5)', '3x^0', '2^3',
'(x+2x(x+2(x+1)x))', '(x+1)(x-1)', '(x+1)(y+1)', '(x+y+t)(q+x+7)'];
var solutionHTML = '';
for (var i = 0; i<problems.length; i++) {
solutionHTML += problems[i] + ' => ' + expand(problems[i]).toHtml() + '<br>';
}
document.body.innerHTML = solutionHTML;
</script>
</html>
It outputs:

display the recursion line by line

I am trying to make a function in javascript that would expand/split a string with dashes and show the process ( line by line ) using recursion.
for example, the string "anna" would become:
expand("anna") = expand("an")+"---"+expand("na") ->
"a"+"---"+"n"+"---"+"n"+"---"+"a"
and the desired output would be:
anna
an---na
a---n---n---a
I have achieved doing the following so far (I know it might not be the solution I am looking):
expand("anna") = an+"---"+expand("na")
= an+"---"+n+"---"+expand("a");
= an+"---"+n+"---+"a"
the output I am getting is:
an---n---a
I can't seem to concatenate the head though to do the first example.
My javascript function of expand is as follows:
function expand(word) {
if (word.length<=1) {
return word;
} else {
mid = word.length/2;
return word.substr(0,mid) + " " + expand(word.substr(mid,word.length));
}
}
document.write(expand("anna"));
I would need some tips to do this, otherwise (if it's the wrong stackexchange forum), please guide me where to post it.
this is my crazy attempt
var Word = function(str) {
this.isSplitable = function() {
return str.length > 1;
}
this.split = function() {
var p = Math.floor(str.length / 2);
return [
new Word(str.substr(0,p)),
new Word(str.substr(p,p+1))
];
}
this.toString = function() {
return str;
}
}
var expand = function(words) {
var nwords = [];
var do_recur = false;
words.forEach(function(word){
if(word.isSplitable()) {
var splitted = word.split();
nwords.push(splitted[0]);
nwords.push(splitted[1]);
do_recur = true;
}else{
nwords.push(word);
}
});
var result = [];
nwords.forEach(function(word){
result.push( word.toString() );
});
var result = result.join("--") + "<br/>";
if(do_recur) {
return result + expand(nwords);
}else{
return "";
}
}
document.write( expand([new Word("anna")]) );
This is what you need
expand = function(word) {
return [].map.call(word, function(x) {return x+'---'}).join('')
};
The joy of functional programming.
And with added code to deal with last character:
function expand(word) {
return [].map.call(word, function(x, idx) {
if (idx < word.length - 1)
return x+'---';
else return x
}).join('')
}
As I said that it is impossible to display the "process" steps of recursion while using recursion, here is a workaround that will output your desired steps:
var levels = [];
function expand(word, level) {
if (typeof level === 'undefined') {
level = 0;
}
if (!levels[level]) {
levels[level] = [];
}
levels[level].push(word);
if (word.length <= 1) {
return word;
} else {
var mid = Math.ceil(word.length/2);
return expand(word.substr(0, mid), level+1) + '---' + expand(word.substr(mid), level+1);
}
}
expand('anna');
for (var i = 0; i < levels.length; i++) {
console.log(levels[i].join('---'));
}
to see all steps the best that I whold do is:
function expand(word) {
if (word.length<=1) {
return word;
} else {
var mid = word.length/2;
var str1 = word.substr(0,mid);
var str2 = word.substr(mid,word.length);
document.write(str1 + "---" + str2 + "<br></br>");
return expand(str1) + "---" + expand(str2);
}
}
document.write(expand("anna"));
You have to return the two parts of the string:
function expand(word) {
output="";
if (word.length<=1) {
output+=word;
return output;
} else
{
var mid = word.length/2;
output+=word.substr(0,mid)+"---"+word.substr(mid)+" \n";//this line will show the steps.
output+=expand(word.substr(0,mid))+"---"+expand(word.substr(mid,word.length-1))+" \n";
return output;
}
}
console.log(expand("anna"));
Edit:
I added the output var and in every loop I concatenate the new output to it.
It should do the trick.
Hope the problem is in your first part. According to your algorithm, you are splitting your string anna in to two parts,
an & na
so you need to expand both parts until the part length is less than or equal to one. so your required function is the below one.
function expand(word) {
if (word.length<=1) {
return word;
} else {
mid = word.length/2;
return expand(word.substr(0,mid)) + " --- " + expand(word.substr(mid,word.length));
}
}
document.write(expand("anna"));

Is there any native function to convert json to url parameters?

I need convert json object to url form like: "parameter=12&asd=1"
I done with this:
var data = {
'action':'actualiza_resultado',
'postID': 1,
'gl': 2,
'gl2' : 3
};
var string_=JSON.stringify(data);
string_=string_.replace(/{/g, "");
string_=string_.replace(/}/g, "");
string_=string_.replace(/:/g, "=")
string_=string_.replace(/,/g, "&");
string_=string_.replace(/"/g, "");
But i wonder if there any function in javascript or in JSON object to do this?
Use the URLSearchParams interface, which is built into browsers and Node.js starting with version 10, released in 2018.
const myParams = {'foo': 'hi there', 'bar': '???'};
const u = new URLSearchParams(myParams).toString();
console.log(u);
Old answer: jQuery provides param that does exactly that. If you don't use jquery, take at look at the source.
Basically, it goes like this:
url = Object.keys(data).map(function(k) {
return encodeURIComponent(k) + '=' + encodeURIComponent(data[k])
}).join('&')
Using ES6 syntax:
var data = {
'action':'actualiza_resultado',
'postID': 1,
'gl': 2,
'gl2' : 3
};
let urlParameters = Object.entries(data).map(e => e.join('=')).join('&');
console.log(urlParameters);
I made an implementation that support nested objects and arrays i.e.
var data = {
users: [
{
"name": "jeff",
"tasks": [
"Do one thing",
"Do second thing"
]
},
{
"name": "rick",
"tasks": [
"Never gonna give you up",
"Never gonna let you down"
]
}
]
}
Will be:
users[0][name]=jeff&users[0][tasks][0]=Do%20one%20thing&users[0][tasks][1]=Do%20second%20thing&users[1][name]=rick&users[1][tasks][0]=Never%20gonna%20give%20you%20up&users[1][tasks][1]=Never%20gonna%20let%20you%20down
So, here's the implementation:
var isObj = function(a) {
if ((!!a) && (a.constructor === Object)) {
return true;
}
return false;
};
var _st = function(z, g) {
return "" + (g != "" ? "[" : "") + z + (g != "" ? "]" : "");
};
var fromObject = function(params, skipobjects, prefix) {
if (skipobjects === void 0) {
skipobjects = false;
}
if (prefix === void 0) {
prefix = "";
}
var result = "";
if (typeof(params) != "object") {
return prefix + "=" + encodeURIComponent(params) + "&";
}
for (var param in params) {
var c = "" + prefix + _st(param, prefix);
if (isObj(params[param]) && !skipobjects) {
result += fromObject(params[param], false, "" + c);
} else if (Array.isArray(params[param]) && !skipobjects) {
params[param].forEach(function(item, ind) {
result += fromObject(item, false, c + "[" + ind + "]");
});
} else {
result += c + "=" + encodeURIComponent(params[param]) + "&";
}
}
return result;
};
var data = {
users: [{
"name": "jeff",
"tasks": [
"Do one thing",
"Do second thing"
]
},
{
"name": "rick",
"tasks": [
"Never gonna give you up",
"Never gonna let you down"
]
}
]
}
document.write(fromObject(data));
You don't need to serialize this object literal.
Better approach is something like:
function getAsUriParameters(data) {
var url = '';
for (var prop in data) {
url += encodeURIComponent(prop) + '=' +
encodeURIComponent(data[prop]) + '&';
}
return url.substring(0, url.length - 1)
}
getAsUriParameters(data); //"action=actualiza_resultado&postID=1&gl=2&gl2=3"
Something I find nicely looking in ES6:
function urlfy(obj) {
return Object
.keys(obj)
.map(k => `${encodeURIComponent(k)}=${encodeURIComponent(obj[k])}`)
.join('&');
}
Later update (same thing, maybe a bit cleaner):
const urlfy = obj => Object
.keys(obj)
.map(k => encodeURIComponent(k) + '=' + encodeURIComponent(obj[k]))
.join('&');
Like #georg said, you can use JQuery.param for flat objects.
If you need to process complex objects, you can use JsonUri, a python package that does just that. There is JavaScript library for it as well
Disclaimer: I am the author of JSONURI
Edit: I learned much later that you can also just base64 encode your payload - most languages as support for base64 encoding/decoding
Example
x = {name: 'Petter', age: 47, places: ['Mozambique', 'Zimbabwe']}
stringRep = JSON.stringify(x)
encoded = window.btoa(stringRep)
Gives you eyJuYW1lIjoiUGV0dGVyIiwiYWdlIjo0NywicGxhY2VzIjpbIk1vemFtYmlxdWUiLCJaaW1iYWJ3ZSJdfQ==, which you can use as a uri parameter
decoded = window.atob(encoded)
originalX = JSON.parse(decoded)
Needless to say, it comes with its own caveats
But i wonder if there any function in javascript
Nothing prewritten in the core.
or json to do this?
JSON is a data format. It doesn't have functions at all.
This is a relatively trivial problem to solve though, at least for flat data structures.
Don't encode the objects as JSON, then:
function obj_to_query(obj) {
var parts = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
parts.push(encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]));
}
}
return "?" + parts.join('&');
}
alert(obj_to_query({
'action': 'actualiza_resultado',
'postID': 1,
'gl': 2,
'gl2': 3
}));
There isn't a standard way to encode complex data structures (e.g. with nested objects or arrays). It wouldn't be difficult to extend this to emulate the PHP method (of having square brackets in field names) or similar though.
This one processes arrays with by changing the nameinto mutiple name[]
function getAsUriParameters (data) {
return Object.keys(data).map(function (k) {
if (_.isArray(data[k])) {
var keyE = encodeURIComponent(k + '[]');
return data[k].map(function (subData) {
return keyE + '=' + encodeURIComponent(subData);
}).join('&');
} else {
return encodeURIComponent(k) + '=' + encodeURIComponent(data[k]);
}
}).join('&');
};
Best solution for Vanilla JavaScript:
var params = Object.keys(data)
.filter(function (key) {
return data[key] ? true : false
})
.map(function (key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(data[key])
})
.join('&');
PS: The filter is used here to remove null or undefined parameters. It makes the url look cleaner.
The custom code above only handles flat data. And JQuery is not available in react native. So here is a js solution that does work with multi-level objects and arrays in react native.
function formurlencoded(data) {
const opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
let sorted = Boolean(opts.sorted),
skipIndex = Boolean(opts.skipIndex),
ignorenull = Boolean(opts.ignorenull),
encode = function encode(value) {
return String(value).replace(/(?:[\0-\x1F"-&\+-\}\x7F-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g, encodeURIComponent).replace(/ /g, '+').replace(/[!'()~\*]/g, function (ch) {
return '%' + ch.charCodeAt().toString(16).slice(-2).toUpperCase();
});
},
keys = function keys(obj) {
const keyarr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Object.keys(obj);
return sorted ? keyarr.sort() : keyarr;
},
filterjoin = function filterjoin(arr) {
return arr.filter(function (e) {
return e;
}).join('&');
},
objnest = function objnest(name, obj) {
return filterjoin(keys(obj).map(function (key) {
return nest(name + '[' + key + ']', obj[key]);
}));
},
arrnest = function arrnest(name, arr) {
return arr.length ? filterjoin(arr.map(function (elem, index) {
return skipIndex ? nest(name + '[]', elem) : nest(name + '[' + index + ']', elem);
})) : encode(name + '[]');
},
nest = function nest(name, value) {
const type = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : typeof value === 'undefined' ? 'undefined' : typeof(value);
let f = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
if (value === f) f = ignorenull ? f : encode(name) + '=' + f; else if (/string|number|boolean/.test(type)) f = encode(name) + '=' + encode(value); else if (Array.isArray(value)) f = arrnest(name, value); else if (type === 'object') f = objnest(name, value);
return f;
};
return data && filterjoin(keys(data).map(function (key) {
return nest(key, data[key]);
}));
}
The conversion from a JSON string to a URL query string can be done in a single line:
const json = '{"action":"actualiza_resultado","postID":1,"gl":2,"gl2":3}';
const queryString = new URLSearchParams(JSON.parse(json)).toString();
queryString would then be set to "action=actualiza_resultado&postID=1&gl=2&gl2=3".
Based on georg's answer, but also adding ? before the string and using ES6:
const query = !params ? '': Object.keys(params).map((k, idx) => {
let prefix = '';
if (idx === 0) {
prefix = '?';
}
return prefix + encodeURIComponent(k) + '=' + encodeURIComponent(params[k]);
}).join('&');
As most of the answers only convert flat objects to query parameters, I would like to share mine.
This function can handle flat objects, as well as nested arrays/objects while only using plain JS.
function incapsulateInBrackets(key)
{
return '[' + key + ']';
}
function encode(object, isSubEncode=false, prefix = '')
{
let parts = Object.keys(object).map( (key) => {
let encodedParts = [];
if(Array.isArray(object[key]))
{
object[key].map(function(innerKey, index){
encodedParts.push( encode(object[key][index], true, prefix + key + incapsulateInBrackets(index)));
});
}
else if(object[key] instanceof Object)
{
Object.keys(object[key]).map( (innerKey) => {
if(Array.isArray(object[key][innerKey]))
{
encodedParts.push( encode(object[key][index], true, prefix + incapsulateInBrackets(key) + incapsulateInBrackets(innerKey)) );
}
else
{
encodedParts.push( prefix + incapsulateInBrackets(key) + incapsulateInBrackets(innerKey) + '=' + object[key][innerKey] );
}
});
}
else
{
if(isSubEncode)
{
encodedParts.push( prefix + incapsulateInBrackets(key) + '=' + object[key] );
}
else
{
encodedParts.push( key + '=' + object[key] );
}
}
return encodedParts.join('&');
});
return parts.join('&');
}
Make a utility if you have nodejs
const querystring = require('querystring')
export function makeQueryString(params): string {
return querystring.stringify(params)
}
import example
import { makeQueryString } from '~/utils'
example of use
makeQueryString({
...query,
page
})
Read the latest documentation here.

Categories

Resources