I want to produce an output from a string like this:
str = "1.000;74.85;10.000;62.13;9999;74.85;15000";
To:
1-10 : 74.85
10-9999 : 62.13
9999-15000 : 74.85
So that the indexes end up like this:
1-3 : 2
3-5 : 4
5-7 : 6
And the odd indexes get converted to integers
I wrote some script but the result is not expected and I think that it is too much code. There is probably some other shorter way.
My code:
var str = "1.000;74.85;10.000;62.13;9999;74.85;15000";
var delimiter = ';';
function splitString(stringToSplit, separator) {
return stringToSplit.split(separator);
}
var arr = splitString(str, delimiter);
var oddElement = [];
var evenElement = [];
for (var i = 0; i < arr.length; i++) {
if ((i % 2) === 0) {
oddElement.push(parseInt(arr[i]))
} else if ((i % 2) != 0) {
evenElement.push(arr[i]);
}
}
function duplicateElements(array, times) {
return array.slice(1,-1).reduce((res, current) => {
return res.concat(Array(times).fill(current));
}, []);
}
oddElement = duplicateElements(oddElement, 2);
oddElement.unshift(parseInt(arr[0]));
oddElement.push(parseInt(arr[arr.length - 1]));
temp = [];
for (var i = 0; i < oddElement.length; i ++) {
temp.push(oddElement[i] + '-' + oddElement[++i]);
}
evenElement.forEach(function(el) {
for (var i = 0; i < temp.length; i++) {
console.log(temp[i] + ":" + el);
}
})
console.log(temp);
console.log(evenElement);
var str = "1.000;74.85;10.000;62.13;9999;74.85;15000";
var arr = str.split(';');
var len = arr.length;
var data = [];
for (i = 1; i < arr.length - 1; i+=2) {
data.push(arr[i - 1] + '-' + arr[i + 1] + ' : ' + arr[i]);
}
This would be a functional way to do it:
Split
Parse each value
create objects containing start(s), end(e) and value(v) for each range
(optional) map over objects to make strings
const str = "1.000;74.85;10.000;62.13;9999;74.85;15000";
function format1(s, d = ';') {
return s
.split(d)
.map(n => parseFloat(n))
.reduce((r, n, i, a) => {
if (i > 1 && i % 2 === 0)
r.push({
s: a[i - 2],
v: a[i - 1],
e: n
});
return r;
}, []);
}
const formatted1 = format1(str);
const formatted2 = formatted1.map(({
s,
v,
e
}) => `${s}-${e} : ${v}`);
console.log(formatted1);
console.log(formatted2);
You can just use a single loop and append your answer to a string one line at a time. An easy way to design this type of logic is to look at your desired result by index in the split array:
parseInt(splitStr[1]) + "-" + parseInt(splitStr[3]) + " : " + splitStr[2]
Then just figure out how to get that same result on each iteration of the loop:
str = "1.000;74.85;10.000;62.13;9999;74.85;15000";
splitStr = str.split(";");
outputStr = "";
for (let i = 0 ; i < splitStr.length - 2 ; i += 2) {
outputStr += parseInt(splitStr[i]) + "-" + parseInt(splitStr[i + 2]) + " : " + splitStr[i + 1] + "\n";
}
console.log(outputStr);
Related
I Need to get this output:
1
2 3
4 5 6
7 8 9 10
11 12 13 14 15
What I've tried so far:
function getPyramid() {
let nums = 0;
for (let i = 1; i <= 15; i++) {
for (let n = 1; n < i; n++) {
console.log(n);
}
console.log('<br/>');
}
return nums;
}
getPyramid();
It is possible to do with one single loop
function getPyramid() {
let nums = 0;
let count = 1;
let numbers = ''
for (let i = 0; i <= 15; i++) {
if(count === nums){
count++
nums = 0;
console.log(numbers)
numbers = ''
}
nums ++
numbers += ' ' + (i +1)
}
}
getPyramid();
Or like this you can specify amount of rows..
function getPyramid(rows) {
let nums = 0;
let count = 1;
let numbers = ''
let i = 1
while (count < rows + 1 ) {
if(count === nums){
count++
nums = 0;
console.log(numbers)
numbers = ''
}
nums ++
numbers += ' ' + i
i++;
}
}
getPyramid(5);
for (let i = 1 ; i <= 5; i++)
{
let s = []
for (let x = i * (i - 1) / 2 + 1; x <= i * (i + 1) / 2; x++)
{
s.push(x)
}
console.log(s.join(" "))
}
Apart from notes given by jnpdx in the comments, I'd add some:
for better convention between programmers we tend to name varible nested in for-loop: i, j
<br/> for HTML new line, In JS we do \n for that!
number++ is same number += 1
Conditional_Operator (expression)?true:false instead of if/else
function getPyramid(Lines) {
let number = 1; // the counter to display on each line of pyramid!
for (let i = 1; i <= Lines; i++) {
let str = '';//line to display
for (let j = 1; j <= i; j++) {
str += number++;//incrementing counter
str += j!=i ? ' ' : ''; //to make space, but not at the end of line.
}
console.log(str);//display that line
}
}
getPyramid(5);
A completely unnecessary attempt to do this in a functional style:
const ranged_array = (from, to) =>
Array.from({ length: to - from + 1 }, (_, i) => i + from);
const pyramid = (lines) =>
ranged_array(1, lines)
.reduce((a, v, i) => {
const prev = a[i - 1];
const last_num = prev && prev[prev.length - 1] || 0;
a.push(ranged_array(last_num + 1, last_num + v));
return a;
}, [])
.map((v) => v.join(' '))
.join("\n");
console.log(pyramid(5));
Hello so what I want to do is split array of names into more arrays of names and each arrays element joined together should be smaller than specific amount of characters and none of the strings should be split in half. if it needs to be split in half then move it to the next array.
so an example would be.
Input: arr: ["george","ben","bob","alex","robert"] amount_of_characters: 10
Output: [["george","ben"],["bob","alex"],["robert"]]
const arr = ["george","ben","bob","alex","robert"];
const amount_of_characters = 10;
const result = [];
let sumChars = 0;
for (let i = 0; i < arr.length; i++) {
const word = arr[i];
if (word.length + sumChars > amount_of_characters) {
result.push([word])
sumChars = 0;
}
else {
!result.length ? result.push([word]) : result[result.length - 1].push(word);
}
sumChars += word.length;
};
console.log(result);
You can easily achieve the result as:
const arr = ['george', 'ben', 'bob', 'alex', 'robert'];
const amount_of_characters = 10;
let currentTotal = 0;
const result = [];
for (let i = 0; i < arr.length; i++) {
const curr = arr[i];
if (currentTotal + curr.length <= amount_of_characters) {
currentTotal += curr.length;
const last = result[result.length - 1];
!last ? result.push([curr]) : result[result.length - 1].push(curr);
} else {
currentTotal = 0;
result.push([]);
i--;
}
}
console.log(result);
function split(arr, amount_of_characters){
let final_arr = [];
let i = 0; // This will be used to denote which position on the original array should be filled
let j = 0; // This will be used to denote which position on the final array should be filled
while (i < arr.length){
// Create a new array in the array
final_arr[j] = [];
let current_character_count = 0;
// Iterate over the input array
while (i < arr.length && arr[i].length + current_character_count < amount_of_characters){
final_arr[j].push(arr[i]);
current_character_count += arr[i].length;
i++;
}
j++;
}
}
You could use a for-of loop and access the last element of the current group using Array.prototype.at():
const groupByUpToNCharacters = (arr, n) => {
const groups = [[]];
let currGroupLength = 0;
for (const word of arr) {
const wordLength = word.length;
if (currGroupLength + wordLength <= n) {
groups.at(-1).push(word);
currGroupLength += wordLength;
} else {
groups.push([word]);
currGroupLength = wordLength;
}
}
return groups;
}
const arr = ["george", "ben", "bob", "alex", "robert"];
const groupedArr = groupByUpToNCharacters(arr, 10);
console.log(groupedArr);
So, what is required here is an algorithm to achieve the expected result. While multiple answers above have given elegant solutions, the below solutions use a recursive approach.
Solution - Style-1:
const joinUptoLen1 = (arr = [], mlen, i = 0) => (
i < arr.length - 1 ?
arr[i].length + arr[i + 1].length < mlen ?
[
[arr[i], arr[i + 1]]
].concat(joinUptoLen1(arr, mlen, i + 2)) :
[
[arr[i]]
].concat(joinUptoLen1(arr, mlen, i + 1)) :
i === arr.length - 1 ?
[
[arr[i]]
] :
[]
);
The same solution written another way is shown below:
Solution - Style-2:
const joinUptoLen2 = (arr = [], mlen, i = 0) => {
if (i < arr.length - 1) {
if (arr[i].length + arr[i + 1].length < mlen) {
return [
[arr[i], arr[i + 1]]
].concat(joinUptoLen2(arr, mlen, i + 2));
} else {
return [
[arr[i]]
].concat(joinUptoLen2(arr, mlen, i + 1));
}
} else {
if (i === arr.length - 1) return [
[arr[i]]
];
return [];
}
};
Approach is very simple. Check if sum-of-lengths of 2 consequent array-elements is lesser than the input-length. If so, make an array of the 2 elements and push this new-array into the result-array. If not, push an array with just the one element into the result-array. Recursively follow the same and handle the edge-scenario (if the last element was not included into a pair).
And here's a code snippet for quick-demo:
const inpArr1 = ["george", "ben", "bob", "alex", "robert"];
const inpArr2 = ["george", "ben", "bob", "alex", "robert", "pat"];
const splitLen = 10;
const joinUptoLen1 = (arr = [], mlen, i = 0) => (
i < arr.length - 1 ?
arr[i].length + arr[i + 1].length < mlen ? [
[arr[i], arr[i + 1]]
].concat(joinUptoLen1(arr, mlen, i + 2)) : [
[arr[i]]
].concat(joinUptoLen1(arr, mlen, i + 1)) :
i === arr.length - 1 ? [
[arr[i]]
] : []
);
const joinUptoLen2 = (arr = [], mlen, i = 0) => {
if (i < arr.length - 1) {
if (arr[i].length + arr[i + 1].length < mlen) {
return [
[arr[i], arr[i + 1]]
].concat(joinUptoLen2(arr, mlen, i + 2));
} else {
return [
[arr[i]]
].concat(joinUptoLen2(arr, mlen, i + 1));
}
} else {
if (i === arr.length - 1) return [
[arr[i]]
];
return [];
}
};
console.log('style-1 results: ', joinUptoLen1(inpArr1, splitLen));
console.log('style-2 results: ', joinUptoLen2(inpArr1, splitLen));
const foo = function (arr, max) { // arr - input, max - max characters in one array
const result = [];
for (let i = 0; i < arr.length; i++) {
let cur = [];
if (arr[i].length < max && i !== arr.length - 1) {
let sum = arr[i].length;
cur.push(arr[i]);
while (sum <= max) {
i++;
if (arr[i].length + sum <= max) {
sum += arr[i].length;
cur.push(arr[i]);
} else {
sum = max + 1;
i--;
}
}
} else cur.push(arr[i]);
result.push(cur);
}
return result;
};
Another way of writing it using Array.reduce():
const input = ["george","ben","bob","alex","Robert"];
let idx=0;
const output = (amount_of_characters)=>{
return input.reduce((acc,curr)=>{
acc[idx]?null: acc.push([]);
acc[idx].join('').length + curr.length <= amount_of_characters?
acc[idx].push(curr):(idx++, acc.push([]), acc[idx].push(curr));
return acc;
},[])
}
console.log(output(10));
This is the problem:
Complete the function splitPairs such that it splits the input string into pairs of characters. If the input string has a length that is odd, then it should replace the missing second character of the final pair with an underscore _. Note, an empty string should make your function produce an empty array.
Here is my code (it keeps timing out):
function splitPairs(input) {
let inputArray = input.split('');
let result = [];
if (inputArray.length % 2 !== 0) {
for (let i = 0; i < inputArray.length; i + 2) {
let pair = inputArray[i] + inputArray[i+1];
//push that onto the result array
result.push(pair);
}
result.push(inputArray[inputArray.length - 1] + '_');
} else {
for (let i = 0; i < inputArray.length; i + 2) {
let pair = inputArray[i] + inputArray[i+1];
result.push(pair);
}
}
return result;
}
What am I doing wrong and what is the proper way to solve this problem? It would be better if I could write the solution myself but I could use help to know what methods I should use to solve it
It's timing out because you're not incrementing i. i + 2 computes the new value but doesn't assign it anywhere. You can update i by doing i += 2 which is shorthand for i = i + 2.
You need to increment using i+=2. Also, there are some mistakes in the solution:
function splitPairs(input) {
let inputArray = input.split('');
let result = [];
if(!inputArray)
return result;
if (inputArray.length % 2 !== 0) {
for (let i = 0; i < inputArray.length-1; i+=2) {
let pair = inputArray[i] + inputArray[i+1];
result.push(pair);
}
result.push(inputArray[inputArray.length - 1] + '_');
} else {
for (let i = 0; i < inputArray.length; i += 2) {
let pair = inputArray[i] + inputArray[i+1];
result.push(pair);
}
}
return result;
}
console.log(splitPairs(""));
console.log(splitPairs("abcd"));
console.log(splitPairs("abcde"));
A simpler solution (with one loop) as mentioned in the comments would be:
function splitPairs(input) {
let inputArray = input.split('');
let result = [];
if(!inputArray)
return result;
let odd = (inputArray.length % 2 !== 0);
let len = (odd) ? inputArray.length-1 : inputArray.length;
for (let i = 0; i < len; i+=2) {
let pair = inputArray[i] + inputArray[i+1];
result.push(pair);
}
if(odd)
result.push(inputArray[inputArray.length - 1] + '_');
return result;
}
console.log(splitPairs(""));
console.log(splitPairs("abcd"));
console.log(splitPairs("abcde"));
You can use a one(two) liner
var result=str.split(/(..)/).filter(v=>v)
if (result[result.length-1].length==1) result[result.length-1]+="_"
You can do it like this
function splitPairs(input) {
return input.split('').map((c, i) => {
if (i % 2 !== 0) return;
if (input[i+1]) {
return input[i] + input[i+1];
}
return input[i] + '_';
}).filter(pair => pair);
}
function insertDash(str) {
var arr = str.split("");
for (var i = 0; i < arr.length; i++) {
if (arr[i] % 2 != 0 && arr[i + 1] % 2 != 0) {
var x = arr.splice(i + 1, 0, '-');
}
}
return arr;
}
console.log(insertDash("99999"));
You can use a String#replace with a regular expression with a lookahead:
function insertDash(string) {
return string.replace(/([13579](?=[13579]))/g, "$1-");
}
console.log(insertDash("99999"));
console.log(insertDash("1122334455"));
The other option is to use Array#reduce to create the string:
function insertDash(string) {
return string.split('').reduce(function(s, c, i, arr) {
return s + c + (c % 2 && arr[i + 1] % 2 ? '-' : '');
}, '');
}
console.log(insertDash("99999"));
console.log(insertDash("1122334455"));
You could iterate from the end of the array, because you probably insert a dash and the array gets a new length.
If you start at the end, you change not the length of the items which are eligible to test and for inserting a dash.
function insertDash(string) {
var array = string.split(""),
i = array.length;
while (i--) {
if (array[i] % 2 && array[i + 1] % 2) {
array.splice(i + 1, 0, '-');
}
}
return array.join('');
}
console.log(insertDash("99999"));
console.log(insertDash("1122334455"));
Here I have some javascript to run a function for each seperate word in a string:
var input = 'this is some text';
var words = input.split(' ');
$.each(words,function(i){
//Do something
});
But how would I do something similar to run the function for each pair of words in a string? Like this:
this is
is some
some text
Or even triple words:
this is some
is some text
Use a common for loop instead of using a foreach loop
var words = "this is some text".split(' ');
// take the words 2 by 2
for (var i = 0; i < words.length - 1; ++i) {
var currentWord = words[i],
nextWord = words[i + 1];
// do something
}
// take the words 3 by 3
for (var i = 1; i < words.length - 1; ++i) {
var previousWord = words[i - 1],
currentWord = words[i],
nextWord = words[i + 1];
// do something
}
You can also handle the general case.
var PACKET_SIZE = 2;
var words = "this is some text".split(' ');
for (var i = 0; i <= words.length - PACKET_SIZE; ++i) {
var packet = words.slice(i, i + PACKET_SIZE);
// do something
}
Edit: Added greater than or equals to so that the last set of words is also included.
Just a proposal with one loop.
function getN(array, n) {
var result = [];
array.forEach(function (a, i, aa) {
i + n <= aa.length && result.push(aa.slice(i, i + n).join(' '));
});
return result;
}
var input = 'this is some text',
array = input.split(' ');
document.write('<pre>' + JSON.stringify(getN(array, 2), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(getN(array, 3), 0, 4) + '</pre>');
Or with a callback for reduce
function getN(n) {
return function (r, a, i, aa) {
i + n <= aa.length && r.push(aa.slice(i, i + n).join(' '));
return r;
};
}
var input = 'this is some text',
array = input.split(' ');
document.write('<pre>' + JSON.stringify(array.reduce(getN(1), []), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(array.reduce(getN(2), []), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(array.reduce(getN(3), []), 0, 4) + '</pre>');
Just use a for loop with an increment of 2 or 3:
for( var i = 0; i < words.length; i += 2 ) {
//Do something with words[i]
}
You can do,
var input = 'this is some text';
var words = input.split(' ');
var length = 2;
var str;
$.each(words, function(j) {
str = "";
for (i = 0; i < length && (j + i) < words.length; i++) {
str += " " + words[j + i];
}
$("#container").append("<div>" + str + "</div>");
});
you can change the pattern length by changing the value of the length parameter.
Fiddle
The following code is using the split function to give you an array of words, then applies map to transform it into an array of arrays, each the size of n. The join function is used to turn those arrays into space separated strings again.
var s="this is some text made of several words";
var n=2;
var result = s.split(' ').map(function(val,index,arr) {
return arr.slice(index,index+n).join(' ');
});
alert(result);
And if you don't want the groups of words less than n, the ones at the end of the word, you need a bit more code:
var s = "this is some text made of several words";
var n = 3;
var arr = s.split(' ');
var result = arr.slice(0, arr.length - n + 1)
.map(function(val, index) {
return arr.slice(index, index + n).join(' ');
});
alert(result);