I am trying to write a program that takes in an prefix expression and outputs an infix expression. I have examples listed below to help demonstrate what I am talking about. I have pasted my code below, could someone please help me figure out how I can move the symbol between 2 numbers in an expression? Please see example 1 to see my approach on how I tried to get it, but it doesn't work. Any answers would be helpful or tips as to what to do. Thank you for your help!
/* The goal is to take in an expression in prefix notation and output it in infix notation
for example:
+ 1 2 outputs output 1 + 2
+ - 3 4 5 outputs 3 + 4 - 5
% + / - 0 9 3 8 5 outputs 0 % 9 + 3 / 8 - 5
*/
function convert(input){
var x = input.split(''); // splits each variable and stores it in an array
var output = "";
// these are the valid symbols we can take, we will use these later
var symbols = ['+', '-', '*', '/', '%'];
// lets loop through all the values in x, starting at position 0
for(var i = 0; i < x.length; i++){
if(symbols.includes(x[i])) { // we hit a symbol, lets move it between 2 numbers
/* now we need to figure out where to store the symbol. every 2 spaces starting at index 0
we can insert a symbol (so spots like 1 3 5 7 etc). this loop will help us figure out what spot is empty
, and it will store the symbol at that spot [see example 1 for a visualizaton]*/
for(var j = 0; j < input.length; j+=2){
if(output[j] == " "){
// great, we can save the symbol here
output = output + x[i];
}
}
}
// otherwise we have a number on our hands
else{
output = output + x[i];
console.log(output);
}
}
}
console.log(convert("+ 1 2"));
/*
example 1
if I have "+ 1 2"
+ is position 0
1 is position 2
2 is position 4
so the whitespace is at position 1 and 3. these are the spots where we can output the symbols
using the original expression + 1 2
position: value:
-------- | ------
0 | 1
-------- | ------
1 | " "
-------- | ------
2 | +
-------- | ------
3 | " "
-------- | ------
4 | 2
*/
function result_expression(expression, variables) {
let opernads=['+','-','*','/'];
let arr=[...expression.split(" ")];
var len=arr.length;
while(len>0){
let d1=arr[len-1]
let d2=arr[len-2]
let d3=arr[len-3]
if(opernads.includes(d3)){
if(isNaN(d2)){
let tmp=variables[d2]
d2=tmp;
}
if(isNaN(d1)){
let tmp1=variables[d1]
d1=tmp1;
}
let a=d2.toString().concat(d3).concat(d1)
delete arr[len-1]
delete arr[len-2]
delete arr[len-3]
let na=[];
arr[len-3]=eval(a)
arr.forEach(e=>{
if(!(typeof e==='undefined')){
na.push(e)
}
})
arr=[...na]
console.log('arr',arr)
len=arr.length;
// arr=[...newar]
// len=arr.length
}else{
len--
}
if(len==1){
return arr[0]
}
}
}
//let expression="+ 6 * - 4 + 2 3 8";
//let expression="+ 6 * - 4 a b + 2 3 8";
let expression="+ * 6 5 3 2 2";
let variables={a:20,b:1}
let k=result_expression(expression, variables);
console.log('finalresult',k)
So long as you're only using simple expressions, I would suggest dividing the input into two arrays, numbers and symbols, and then merging them together.
var symbols = ['+', '-', '*', '/', '%'];
function convert(input) {
var
response = '',
infixes = [],
numbers = [];
// Divide input into two arrays, infixes (or symbols) and numbers
infixes = input.split(' ').filter(function(o) {
if (symbols.includes(o)) {
return true;
} else {
numbers.push(o);
}
});
// Merge arrays
for (let i = 0; i < numbers.length; i++) {
if (infixes[i]) {
response =
response +
numbers[i] + ' ' +
infixes[i] + ' ';
} else {
response =
response + numbers[i] + ' ';
}
}
response = response.slice(0, -1);
return response;
};
This function works for all your examples, but if you need to make it more intelligent you can easily modify and test the above function on codepen here.
Related
It is a counter function for descending number. I throw any number and it start to countdown to zero and I add space between them but the Problem is the last space! How can I remove it??
function countDown(number) {
var s = "";
for (let i = number; i >= 0; i--) {
s += i + " ";
}
console.log("{" + s + "}"); // I add the brackets to show the last space
}
countDown(10)
// result is : {10 9 8 7 6 5 4 3 2 1 0 }
This is a great use case for the Array.join function.
function countDown(number) {
const list = [];
for (let i = number; i >= 0; i--) {
list.push(i);
}
console.log("{" + list.join(' ') + "}");
}
countDown(10)
// result is : {10 9 8 7 6 5 4 3 2 1 0}
This is a common pattern that one has to deal with in loops.
Typically you solve this by having a special case in the beggining or end of a loop. In this example it is easy just to have one in the beggining:
function countDown(number) {
var s = number;
for (let i = number - 1; i >= 0; i--) {
s += " " + i;
}
console.log("{" + s + "}"); // I add the brackets to show the last space
}
countDown(10)
// result is : {10 9 8 7 6 5 4 3 2 1 0}
Just assign s to the number in the beggining and decrease the starting number by 1.
With "low-level" Javascript, without builtins, the trick is to add a delimiter before an item, not after it:
function countDown(number) {
let s = String(number)
for (let i = number - 1; i >= 0; i--)
s += ' ' + i
return s
}
console.log(JSON.stringify(countDown(10)))
If builtins are allowed, you don't even need a loop to produce this result:
result = [...new Array(11).keys()].reverse().join(' ')
console.log(result)
This is a slightly odd/unique request. I am trying to achieve a result where e.g "yes" becomes, "yyes", "yees", "yess", "yyees", "yyess", "yyeess".
I have looked at this: Find all lowercase and uppercase combinations of a string in Javascript which completes it for capitalisation, however my understanding is prohibiting me from manipulating this into character duplication (if this method is even possible to use in this way).
export function letterDuplication(level: number, input: string){
const houseLength = input.length;
if (level == 1){
var resultsArray: string[] = [];
const letters = input.split("");
const permCount = 1 << input.length;
for (let perm = 0; perm < permCount; perm++) {
// Update the capitalization depending on the current permutation
letters.reduce((perm, letter, i) => {
if (perm & 1) {
letters[i] = (letter.slice(0, perm) + letter.slice(perm-1, perm) + letter.slice(perm));
} else {
letters[i] = (letter.slice(0, perm - 1) + letter.slice(perm, perm) + letter.slice(perm))
}
return perm >> 1;
}, perm);
var result = letters.join("");
console.log(result);
resultsArray[perm] = result;
}
If I haven't explained this particularly well please let me know and I'll clarify. I'm finding it quite the challenge!
General idea
To get the list of all words we can get from ordered array of letters, we need to get all combinations of letters, passed 1 or 2 times into word, like:
word = 'sample'
array = 's'{1,2} + 'a'{1,2} + 'm'{1,2} + 'p'{1,2} + 'l'{1,2} + 'e'{1,2}
Amount of all possible words equal to 2 ^ word.length (8 for "yes"), so we can build binary table with 8 rows that represent all posible combinations just via convering numbers from 0 to 7 (from decimal to binary):
0 -> 000
1 -> 001
2 -> 010
3 -> 011
4 -> 100
5 -> 101
6 -> 110
7 -> 111
Each decimal we can use as pattern for new word, where 0 means letter must be used once, and 1 - letter must be used twice:
0 -> 000 -> yes
1 -> 001 -> yess
2 -> 010 -> yees
3 -> 011 -> yeess
4 -> 100 -> yyes
5 -> 101 -> yyess
6 -> 110 -> yyees
7 -> 111 -> yyeess
Code
So, your code representation may looks like this:
// Initial word
const word = 'yes';
// List of all possible words
const result = [];
// Iterating (2 ^ word.length) times
for (let i = 0; i < Math.pow(2, word.length); i++) {
// Get binary pattern for each word
const bin = decToBin(i, word.length);
// Make a new word from pattern ...
let newWord = '';
for (let i = 0; i < word.length; i++) {
// ... by adding letter 1 or 2 times based on bin char value
newWord += word[i].repeat(+bin[i] ? 2 : 1);
}
result.push(newWord);
}
// Print result (all possible words)
console.log(result);
// Method for decimal to binary convertion with leading zeroes
// (always returns string with length = len)
function decToBin(x, len) {
let rem, bin = 0, i = 1;
while (x != 0) {
rem = x % 2;
x = parseInt(x / 2);
bin += rem * i;
i = i * 10;
}
bin = bin.toString();
return '0'.repeat(len - bin.length) + bin;
}
Maybe this example can help you. It's a bit not neat and not optimal, but it seems to work:
function getCombinations(word = '') {
const allCombination = [];
const generate = (n, arr, i = 0) => {
if (i === n) {
return allCombination.push([...arr]);
} else {
arr[i] = 0;
generate(n, arr, i + 1);
arr[i] = 1;
generate(n, arr, i + 1);
}
}
generate(word.length, Array(word.length).fill(0));
return allCombination.map((el) => {
return el.map((isCopy, i) => isCopy ? word[i].repeat(2) : word[i]).join('')
});
}
console.log(getCombinations('yes'));
console.log(getCombinations('cat'));
Given the triangle of consecutive odd numbers:
1
3 5
7 9 11
13 15 17 19
21 23 25 27 29
// Calculate the row sums of this triangle from the row index (starting at index 1) e.g.:
rowSumOddNumbers(1); // 1
rowSumOddNumbers(2); // 3 + 5 = 8
I tried to solve this using for loops:
function rowSumOddNumbers(n){
let result = [];
// generate the arrays of odd numbers
for(let i = 0; i < 30; i++){
// generate sub arrays by using another for loop
// and only pushing if the length is equal to current j
let sub = [];
for(let j = 1; j <= n; j++){
// if length === j (from 1 - n) keep pushing
if(sub[j - 1].length <= j){
// and if i is odd
if(i % 2 !== 0){
// push the i to sub (per length)
sub.push(i);
}
}
}
// push everything to the main array
result.push(sub);
}
// return sum of n
return result[n + 1].reduce(function(total, item){
return total += item;
});
}
My code above is not working. Basically I was planning to 1st generate an array of odd numbers less than 30. Next I need to create a sub array base on the length of iteration (j) that would from 1 - n (passed). Then finally push it to the main array. And then use reduce to get the sum of all the values in that index + 1 (since the index starts at 1).
Any idea what am I missing and how to make this work?
Most code problems involve some analysis first in order to spot patterns which you can then convert into code. Looking at the triangle, you'll see the sum of each row follows a pattern:
1: 1 === 1 ^ 3
2: 3 + 5 = 8 === 2 ^ 3
3: 7 + 9 + 11 = 27 === 3 ^ 3
... etc
So from the analysis above you can see that your code could probably be simplified slightly - I won't post an answer, but think about using Math.pow.
No need for any loops.
function rowSumOddNumbers(n) {
// how many numbers are there in the rows above n?
// sum of arithmetic sequence...
let numbers_before_n_count = (n - 1) * n / 2;
let first_number_in_nth_row = numbers_before_n_count * 2 + 1;
let last_number_in_nth_row = first_number_in_nth_row + 2 * (n - 1);
// sum of arithmetic sequence again...
return n * (first_number_in_nth_row + last_number_in_nth_row) / 2;
}
I am trying to see if I can get my function to determine the "odd man out" in the array living within the function. Specifically, after I take a string, convert it into numbers and push it into an array -- I want it to be able to loop through the output array and return the index of which number is "the odd man out" (i.e. "2 2 2 2 4 6 8 1" should return index 7 as it is the only odd number). However, I'm having trouble figuring out how to return the index, when the function faces both situations that I listed below in the code.
function notSame(numbers){
var notString = parseInt(numbers.replace(/\s+/g, ''), 10),
sNumber = notString.toString(),
output =[];
console.log(sNumber);
for(var i = 0; i < sNumber.length; i+=1) {
output.push(+sNumber.charAt(i));
}
for(var num1 = 0; num1 < output.length; num1++) {
for(var num2 = 1; num2 < output.length; num2++) {
if(output[num1] % output[num2] === 1) {
return num1;
}
}
}
}
notSame("2 2 2 2 4 6 8 1"); /// Situation 1: should output index 7 as it is the only odd number
notSame("5 7 9 2 1" ); ///Situation 2: should output index 4 as it is the only even number
Once you have your integers in the output array,
// test the first three array members
var test = Math.abs(output[0])%2 + Math.abs(output[1])%2 + Math.abs(output[2])%2;
// if the sum of the mods of the first three integers in the
// array is more than 1, the array is mostly odd numbers, hence
// the odd one out will be even, else it will be odd
var outlierIsOdd = test >= 2 ? false : true;
// find the odd one out and return it's index
return output.indexOf(output.filter(function(e){
return (Math.abs(e)%2 === +outlierIsOdd);
})[0]);
You might find it easier to break down the problem into smaller units.
// return an array from a string
function toArray(str) { return str.split(' '); }
// return the element if it's even
function even(el) { return el % 2 === 0; }
// return the index of either true/false
function getIndex(arr, flag) { return arr.indexOf(flag); }
// count how many instances of true are in the array
function count(arr) {
return arr.filter(function (el) {
return el;
}).length;
}
function check(str) {
// return an array of true/false values
var evens = toArray(str).map(even);
// if there is more than 1 true value in `evens`
// return the index of false from the array
// otherwise return the index of the only true element
return count(evens) > 1 ? getIndex(evens, false) : getIndex(evens, true);
}
check('2 2 2 2 4 6 8 1'); // 7
check('5 7 9 2 1'); // 3
check('2 5 2 6 6'); // 1
check('7 7 7 9 1 3 8 1 5') // 6
DEMO
function notSame(string) {
var even = [];
var odd = [];
string.split(" ").forEach(function(e, i) {
string.split(" ")[i] % 2 ? odd.push(i) : even.push(i);
})
even > odd ? document.write(even) : document.write(odd);
}
notSame("2 2 2 2 4 6 8 1");
Fill up 2 arrays with index:
one for odds and one for evens and compare the length.
I am trying in javascript to convert an integer (which I know will be between 0 and 32), to an array of 0s and 1s. I have looked around but couldn't find something that works..
So, if I have an integer as 22 (binary 10110), I would like to access it as:
Bitarr[0] = 0
Bitarr[1] = 1
Bitarr[2] = 1
Bitarr[3] = 0
Bitarr[4] = 1
Any suggestions?
Many thanks
convert to base 2:
var base2 = (yourNumber).toString(2);
access the characters (bits):
base2[0], base2[1], base2[3], etc...
Short (ES6)
Shortest (32 chars) version which fill last bits by zero. I assume that n is your number, b is base (number of output bits):
[...Array(b)].map((x,i)=>n>>i&1)
let bits = (n,b=32) => [...Array(b)].map((x,i)=>(n>>i)&1);
let Bitarr = bits(22,8);
console.log(Bitarr[0]); // = 0
console.log(Bitarr[1]); // = 1
console.log(Bitarr[2]); // = 1
console.log(Bitarr[3]); // = 0
console.log(Bitarr[4]); // = 1
var a = 22;
var b = [];
for (var i = 0; i < 5; i++)
b[i] = (a >> i) & 1;
alert(b);
Assuming 5 bits (it seemed from your question), so 0 <= a < 32. If you like you can make the 5 larger, upto 32 (bitshifting in JavaScript works with 32 bit integer).
This should do
for(int i = 0; i < 32; ++i)
Bitarr[i] = (my_int >> i) & 1;
You can convert your integer to a binary String like this. Note the base 2 parameter.
var i = 20;
var str = i.toString(2); // 10100
You can access chars in a String as if it were an array:
alert(str[0]); // 1
alert(str[1]); // 0
etc...
Building up on previous answers: you may want your array to be an array of integers, not strings, so here is a one-liner:
(1234).toString(2).split('').map(function(s) { return parseInt(s); });
Note, that shorter version, (11).toString(2).split('').map(parseInt) will not work (chrome), for unknown to me reason it converts "0"s to NaNs
In addition, this code gives 32length array
function get_bits(value){
var base2_ = (value).toString(2).split("").reverse().join("");
var baseL_ = new Array(32 - base2_.length).join("0");
var base2 = base2_ + baseL_;
return base2;
}
1 => 1000000000000000000000000000000
2 => 0100000000000000000000000000000
3 => 1100000000000000000000000000000
You might do as follows;
var n = 1071,
b = Array(Math.floor(Math.log2(n))+1).fill()
.map((_,i,a) => n >> a.length-1-i & 1);
console.log(b);
just for the sake of refernce:
(121231241).toString(2).split('').reverse().map((x, index) => x === '1' ? 1 << index : 0).reverse().filter(x => x > 0).join(' + ');
would give you:
67108864 + 33554432 + 16777216 + 2097152 + 1048576 + 524288 + 65536 + 32768 + 16384 + 4096 + 1024 + 512 + 256 + 128 + 8 + 1