Insert multiple strings into a string without adjusting for index changes - javascript

The conundrum I have is as follows: I have an array of the pair of indexes of a string at which one character (the third item in the sub-arrays) must be inserted (note, these pairs can be duplicates), e.g.
let arr = [[0, 6, "7"], [0, 6, "h"], [2, 10, "2"], [12, 17, "j"]];
let my_string = "This is a very important string";
for (let i = 0; i < arr.length; i++) {
// magic code
}
// => my_string now equals "7hth2is i7hs a 2vejry imjportant string";
I can't just insert the character at each index because the next pair of indexes in the array will become out of date, due to the previous pair of indexes changing the string and so causing it to have new indexes for each character.
I've also tried slicing the string based on the index pairs (using them as the start and end indexes) and inserting the characters onto these substrings before merging them all together again, but the issue with this is that if two pairs of indexes overlap, then parts of the original string get duplicated.
NOTE: the array is sorted in order from smallest second index in the pair to largest, as shown above. This can be changed. However, the array will always contain pairs of indexes - i.e. I cannot flatten the array into just indexes because of the third item of the arrays being the character I want to insert.
One other thing I tried was going from the end of the array of index pairs to the start, but again the fact that index pairs can overlap means this does not work.
How would I insert the characters at each index in the array of index pairs?
Thanks in advance for any help.

You could create an object of indicies containing strings, where each string item specifies the string to insert at that index. Eg, from
[[0, 6], [0, 6], [2, 10]]
and an array of characters to insert ['x', 'y', 'z'], construct
{
0: 'xy',
2: 'z',
6: 'xy',
10: 'z'
}
Then you can use a regular expression to match any position (without matching any characters), and use its callback function to look up the current index on the object, and replace with all the characters at that point (if any):
let arr = [[0, 6, "7"], [0, 6, "h"], [2, 10, "2"], [12, 17, "j"]];
const obj = {};
for (const [left, right, char] of arr) {
obj[left] = (obj[left] || '') + char;
obj[right] = (obj[right] || '') + char;
}
const my_string = "This is a very important string";
console.log(
my_string.replace(
/(?:)/g,
(_, index) => obj[index] || ''
)
);

Instead of looping through the array you can loop through the string.
let arr = [[0, 6, "7"], [0, 6, "h"], [2, 10, "2"], [12, 17, "j"]];
let my_string = "This is a very important string";
let str2 = ''
for (let i = 0; i < my_string.length; i++) {
str2 += arr.filter(x => x.includes(i))
.reduce(( total, current) => total + current[2],'') + my_string[i];
}
console.log(str2);
The filter will keep those elements in arr that contains the current index (i) of the loop.
If the filter's output is not empty then reduce will concatenate all their 3rd elements. Finally the current my_string element is added at the end.
If the filter's output is empty, reduce will do nothing, so only the current character in my_string is concatenated to str2.
The result:
7hTh2is i7hs a 2vejry imjportant string

Related

(Javascript) Finding multiple parameters between each other within a user input [duplicate]

I have a one-dimensional array of integer in JavaScript that I'd like to add data from comma separated string, Is there a simple way to do this?
e.g : var strVale = "130,235,342,124 ";
? "123,87,65".split(",").map(Number)
> [123, 87, 65]
Edit >>
Thanks to #NickN & #connexo remarks!
A filter is applicable if you by eg. want to exclude any non-numeric values:
?", ,0,,6, 45,x78,94c".split(",").filter(x => x.trim().length && !isNaN(x)).map(Number)
> [0, 6, 45]
You can use split() to get string array from comma separated string. If you iterate and perform mathematical operation on element of string array then that element will be treated as number by run-time cast but still you have string array. To convert comma separated string int array see the edit.
arr = strVale.split(',');
Live Demo
var strVale = "130,235,342,124";
arr = strVale.split(',');
for(i=0; i < arr.length; i++)
console.log(arr[i] + " * 2 = " + (arr[i])*2);
Output
130 * 2 = 260
235 * 2 = 470
342 * 2 = 684
124 * 2 = 248
Edit, Comma separated string to int Array In the above example the string are casted to numbers in expression but to get the int array from string array you need to convert it to number.
var strVale = "130,235,342,124";
var strArr = strVale.split(',');
var intArr = [];
for(i=0; i < strArr.length; i++)
intArr.push(parseInt(strArr[i]));
You can use the String split method to get the single numbers as an array of strings. Then convert them to numbers with the unary plus operator, the Number function or parseInt, and add them to your array:
var arr = [1,2,3],
strVale = "130,235,342,124 ";
var strings = strVale.split(",");
for (var i=0; i<strVale.length; i++)
arr.push( + strings[i] );
Or, in one step, using Array map to convert them and applying them to one single push:
arr.push.apply(arr, strVale.split(",").map(Number));
just you need to use couple of methods for this, that's it!
var strVale = "130,235,342,124";
var resultArray = strVale.split(',').map(function(strVale){return Number(strVale);});
the output will be the array of numbers.
The split() method is used to split a string into an array of substrings, and returns the new array.
Syntax:
string.split(separator,limit)
arr = strVale.split(',');
SEE HERE
You can split and convert like
var strVale = "130,235,342,124 ";
var intValArray=strVale.split(',');
for(var i=0;i<intValArray.length;i++{
intValArray[i]=parseInt(intValArray[i]);
}
Now you can use intValArray in you logic.
Solution:
var answerInt = [];
var answerString = "1,2,3,4";
answerString.split(',').forEach(function (item) {
answerInt.push(parseInt(item))
});
All of the given answers so far create a possibly unexpected result for a string like ",1,0,-1,, ,,2":
",1,0,-1,, ,,2".split(",").map(Number).filter(x => !isNaN(x))
// [0, 1, 0, -1, 0, 0, 0, 2]
To solve this, I've come up with the following fix:
",1,0,-1,, ,,2".split(',').filter(x => x.trim() !== "").map(Number).filter(x => !isNaN(x))
// [1, 0, -1, 2]
Please note that due to
isNaN("") // false!
and
isNaN(" ") // false
we cannot combine both filter steps.
This is an easy and quick solution when the string value is proper with the comma(,).
But if the string is with the last character with the comma, Which makes a blank array element, and this is also removed extra spaces around it.
"123,234,345,"
So I suggest using push()
var arr = [], str="123,234,345,"
str.split(",").map(function(item){
if(item.trim()!=''){arr.push(item.trim())}
})
There are good solutions in this post but I would like to add one more. Instead of using filter and map I would suggest to use reduce to iterate through all the items just once.
Also I will compare it with the use of a regex looking for digits. Please evaluate which method fits your needs. Here are the examples:
const strA = ',1,0,-2,a3 , 4b,a5b ,21, 6 7,, 8.1'
const arrayOfNumbersA = strA.split(',').reduce((acc, val) => val && !Number.isNaN(+val) ? acc.push(+val) && acc : acc, [])
console.log(arrayOfNumbersA)
// => [1, 0, -2, 21, 8.1] - As you can see in the output the negative numbers
// do work and if the number have characters before or after
// the numbers are removed from since they are treated like NaN.
// Note: in this case the comma is the delimiting each number that will be evaluated in the reduce
const arrayOfNumbersB = strA.match(/[\d.]+/g).map(Number)
console.log(arrayOfNumbersB)
// => [1, 0, 2, 3, 4, 5, 21, 6, 7, 8.1] - As you can see in the output the negative numbers
// are transformed to positives and if the number have characters before or after
// the numbers placed any way.
//Note: that in this case the regex is looking for digits no matter how they are separated.
// FYI: seeing all the steps using the reduce method
const arrayOfNumbersC = strA.split(',').reduce((acc, val) => {
if(val && !Number.isNaN(+val)) {
acc.push(+val)
}
return acc
}, [])
console.log(arrayOfNumbersC)
// => [1, 0, -2, 21, 8.1]
In order to also take string value and avoid crushing we can solve it this way
let strVale = "130,235,342,124 ";
let unformattedArray =strVale.split(',');
const formatArray = (unformattedArray) => {
if (unformattedArray.map(Number).includes(NaN)) {
return unformattedArray;
}
else {
return unformattedArray.map(Number);
}
}
//then every time we want to format we call our function to format for us
console.log(formatArray(unformattedArray));
// or asign a value
let foramttedArray = formatArray(unformattedArray);

Sum of two multi dimensional array

I have a array in JavaScript like this.
var arr=
[
['A'],[1,2,3,4],
['A'],[4,3,2,1],
['B'],[10,12,3,1],
['B'],[1,2,3,4],
.
.
.
.
['AZ'],[1,2,3,4]
]
and I want the output to summarize the array like -
var output=
[
['A'],[5,5,5,5],
['B'],[11,14,6,5],
['AZ'],[1,2,3,4]
]
Thanks.
Script
You can use the following script to achieve what you want to do.
const arr = [
["A"],
[1, 2, 3, 4],
["A"],
[4, 3, 2, 1],
["B"],
[10, 12, 3, 1],
["B"],
[1, 2, 3, 4],
["AZ"],
[1, 2, 3, 4],
];
/**
* Generator to return key-value pairs with array[i] being the key and array[i+1] being the value
* #param {Array<any>} array
*/
function* keyValue(array) {
// make sure we can build pairs (other ways of handling this are also possible)
if (array.length % 2 !== 0)
throw new RangeError(
"Array length must be dividable by 2 without remainder!"
);
for (let i = 0; i < array.length; i += 2) {
yield [array[i], array[i + 1]];
}
}
// here the created key-value pairs
console.log("Key-value pairs created by keyValue() generator function:");
console.log([...keyValue(arr)]);
// loop over key value pairs and sum up all the individul arrays based on the letter assigned to them
const result = [...keyValue(arr)].reduce((all, [[key], array]) => {
// if we don't have values for this letter, assing copy of the array to that letter
if (!all[key]) all[key] = [...array];
// we have some values for that letter already, sum up each value
else all[key] = all[key].map((prev, idx) => prev + array[idx]);
return all;
}, {});
// this would be a "better" result to my mind as there is no point wrapping single string values in arrays
// When using objects the values can easily be accessed in O(1)
console.log(result);
// now transform JS object to array of arrays
console.log("Result:");
const transformed = Object.entries(result).flatMap(([key, value]) => [[key], value]);
console.log(transformed);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Please note: This implementation assumes that the arrays for a given letter have the same length (as is the case in your example).
Explanation
First of all, I use a generator function keyValue() to always group two consecutive values in the array (a key and a value) together. One could also do this differently but once you understand how generators work that's an easy and elegant approach, I think. For this demo I just throw an error if the array is not dividable by 2 without remainder, but one could also handle this more gracefully.
Then, using reduce(), I iterate over the array created by using keyValue() and for each element in the array I check if I've encountered that value before. If I have not, I create a copy of the array (for immutablility) and assign it to the key i.e. a letter. If I have encountered a certain letter before I add up the values that I have previously saved assigned to that letter with the ones I am currently processing. After iteration all sums are calculated and I have a JavaScript object containing the results.
To my mind, this would be a good output because your output is a bit odd, since there is no point storing single letters in an array or even arrays of arrays. Using a JavaScript object is much more convenient and faster for lookups.
Nevertheless, you can easily deduct your result from the created object using flatMap().

sortedIndex for reverse sorted array?

It seems lodash's sortedIndex expects a forward sorted array for its binary search to work. (e.g. [0,1,2,4])
Is there a way to used sortedIndexBy when the array is reverse sorted? (e.g. [4,2,1,0])?
> _.sortedIndex( [0,1,2,4], 3 )
> 3
> _.sortedIndex( [4,2,1,0], 3 )
> 4
To get this to work now, I have to reverse the array, find the sortedIndex, insert the new element, and then un-reverse the array.
Note -- need something which works for sorting strings as well as numbers.
['A','B','D'] into ['D','B','A'] and insert 'C'.
How about _.sortedIndexBy?
Edited: For string comparison, String.prototype.charCodeAt() can help you convert it to Number, then the same logic can be applied.
const arr1 = [0, 1, 2, 4];
const arr2 = [4, 2 ,1, 0];
console.log(_.sortedIndex(arr1, 3 ));
// Similar, but with ranking function.
console.log(_.sortedIndexBy(arr2, 3, function(x) {return -x;}));
const charArr = ['D','B','A'];
// Take the first char and convert to Number
let index = _.sortedIndexBy(charArr, 'C', function(x) {
// Type checks. (If you want it to be general to many types..
if (typeof x === 'string') {
return -x.charCodeAt(0);
} else if (typeof x === 'number') {
return -x;
} // else ... for other types.....
});
console.log('To insert char C, put it to index: ', index);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js"></script>
or by _.sortedIndex, it also has iteratee to rank before 4.0.0
const arr1 = [0, 1, 2, 4];
const arr2 = [4, 2 ,1, 0];
console.log(_.sortedIndex(arr1, 3));
console.log("Reversed order without ranking func: ",_.sortedIndex(arr2, 3));
// Ranking function to inverse the order.
console.log("Reversed order with ranking func: ",_.sortedIndex(arr2, 3, function(x) {return -x;}));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.3.1/lodash.min.js"></script>
Thanks to pilau:
The sortedIndex expects the array is forward sorted, so we can't just put the reverse sorted array and get arr.length - index, and in order to handle vary scenario, I think we need to do either
Reverse array -> get sorted index and put -> reverse it again. or
Get reversed copy by slice and reverse -> get sorted index and calculate by arr.length - index -> inserted to origin array.
To achieve the expected result.

Insert an array in the middle of an existing array. Keep the existing reference intact

Say I have two arrays:
var numbers = [1,3,5,7,9,11];
var letters = ['a','b','c'];
And say I have another reference to the numbers array:
var anotherRef = numbers;
I would like to insert one into the other in a way that modifies the existing array, so that after the operation, anotherRef === numbers.
If I didn't need to maintain the original array, I would do this:
function insert(target, source, position) {
return target.slice(0, position).concat(source, target.slice(position));
}
The problem is, after an insert with this method, the two references point at different arrays:
numbers = insert(numbers, letters, 3);
numbers !== anotherRef; // sadly, true.
If I were adding to the end of the array, I could do this, which is kind of slick:
function insertAtEnd(target, source) {
Array.prototype.push.apply(target, source);
}
Is there a nice way to insert multiple values in place in a JS array?
It looks like you're looking for the splice method:
function insert(target, source, position) {
Array.prototype.splice.apply(target, [position, 0].concat(source));
return target;
}
var numbers = [1,3,5,7,9,11];
var letters = ['a','b','c'];
insert(numbers, letters, 3);
console.log(numbers);
>> [1, 3, 5, "a", "b", "c", 7, 9, 11]
Working example: http://jsfiddle.net/0mwun0ou/1/
function insert(target, source, position) {
Array.prototype.splice.apply(target, [position,0].concat(source));
}
var numbers = [1,3,5,7,9,11];
var letters = ['a','b','c'];
var anotherRef = numbers
insert(numbers, letters, 1)
console.log(anotherRef)
I never touched anotherRef, but on that example the output is:
[1, "a", "b", "c", 3, 5, 7, 9, 11]
For an explanation how to use an array as the third argument of splice check: Is there a way to use Array.splice in javascript with the third parameter as an array?

How to convert comma separated string into numeric array in javascript

I have a one-dimensional array of integer in JavaScript that I'd like to add data from comma separated string, Is there a simple way to do this?
e.g : var strVale = "130,235,342,124 ";
? "123,87,65".split(",").map(Number)
> [123, 87, 65]
Edit >>
Thanks to #NickN & #connexo remarks!
A filter is applicable if you by eg. want to exclude any non-numeric values:
?", ,0,,6, 45,x78,94c".split(",").filter(x => x.trim().length && !isNaN(x)).map(Number)
> [0, 6, 45]
You can use split() to get string array from comma separated string. If you iterate and perform mathematical operation on element of string array then that element will be treated as number by run-time cast but still you have string array. To convert comma separated string int array see the edit.
arr = strVale.split(',');
Live Demo
var strVale = "130,235,342,124";
arr = strVale.split(',');
for(i=0; i < arr.length; i++)
console.log(arr[i] + " * 2 = " + (arr[i])*2);
Output
130 * 2 = 260
235 * 2 = 470
342 * 2 = 684
124 * 2 = 248
Edit, Comma separated string to int Array In the above example the string are casted to numbers in expression but to get the int array from string array you need to convert it to number.
var strVale = "130,235,342,124";
var strArr = strVale.split(',');
var intArr = [];
for(i=0; i < strArr.length; i++)
intArr.push(parseInt(strArr[i]));
You can use the String split method to get the single numbers as an array of strings. Then convert them to numbers with the unary plus operator, the Number function or parseInt, and add them to your array:
var arr = [1,2,3],
strVale = "130,235,342,124 ";
var strings = strVale.split(",");
for (var i=0; i<strVale.length; i++)
arr.push( + strings[i] );
Or, in one step, using Array map to convert them and applying them to one single push:
arr.push.apply(arr, strVale.split(",").map(Number));
just you need to use couple of methods for this, that's it!
var strVale = "130,235,342,124";
var resultArray = strVale.split(',').map(function(strVale){return Number(strVale);});
the output will be the array of numbers.
The split() method is used to split a string into an array of substrings, and returns the new array.
Syntax:
string.split(separator,limit)
arr = strVale.split(',');
SEE HERE
You can split and convert like
var strVale = "130,235,342,124 ";
var intValArray=strVale.split(',');
for(var i=0;i<intValArray.length;i++{
intValArray[i]=parseInt(intValArray[i]);
}
Now you can use intValArray in you logic.
Solution:
var answerInt = [];
var answerString = "1,2,3,4";
answerString.split(',').forEach(function (item) {
answerInt.push(parseInt(item))
});
All of the given answers so far create a possibly unexpected result for a string like ",1,0,-1,, ,,2":
",1,0,-1,, ,,2".split(",").map(Number).filter(x => !isNaN(x))
// [0, 1, 0, -1, 0, 0, 0, 2]
To solve this, I've come up with the following fix:
",1,0,-1,, ,,2".split(',').filter(x => x.trim() !== "").map(Number).filter(x => !isNaN(x))
// [1, 0, -1, 2]
Please note that due to
isNaN("") // false!
and
isNaN(" ") // false
we cannot combine both filter steps.
This is an easy and quick solution when the string value is proper with the comma(,).
But if the string is with the last character with the comma, Which makes a blank array element, and this is also removed extra spaces around it.
"123,234,345,"
So I suggest using push()
var arr = [], str="123,234,345,"
str.split(",").map(function(item){
if(item.trim()!=''){arr.push(item.trim())}
})
There are good solutions in this post but I would like to add one more. Instead of using filter and map I would suggest to use reduce to iterate through all the items just once.
Also I will compare it with the use of a regex looking for digits. Please evaluate which method fits your needs. Here are the examples:
const strA = ',1,0,-2,a3 , 4b,a5b ,21, 6 7,, 8.1'
const arrayOfNumbersA = strA.split(',').reduce((acc, val) => val && !Number.isNaN(+val) ? acc.push(+val) && acc : acc, [])
console.log(arrayOfNumbersA)
// => [1, 0, -2, 21, 8.1] - As you can see in the output the negative numbers
// do work and if the number have characters before or after
// the numbers are removed from since they are treated like NaN.
// Note: in this case the comma is the delimiting each number that will be evaluated in the reduce
const arrayOfNumbersB = strA.match(/[\d.]+/g).map(Number)
console.log(arrayOfNumbersB)
// => [1, 0, 2, 3, 4, 5, 21, 6, 7, 8.1] - As you can see in the output the negative numbers
// are transformed to positives and if the number have characters before or after
// the numbers placed any way.
//Note: that in this case the regex is looking for digits no matter how they are separated.
// FYI: seeing all the steps using the reduce method
const arrayOfNumbersC = strA.split(',').reduce((acc, val) => {
if(val && !Number.isNaN(+val)) {
acc.push(+val)
}
return acc
}, [])
console.log(arrayOfNumbersC)
// => [1, 0, -2, 21, 8.1]
In order to also take string value and avoid crushing we can solve it this way
let strVale = "130,235,342,124 ";
let unformattedArray =strVale.split(',');
const formatArray = (unformattedArray) => {
if (unformattedArray.map(Number).includes(NaN)) {
return unformattedArray;
}
else {
return unformattedArray.map(Number);
}
}
//then every time we want to format we call our function to format for us
console.log(formatArray(unformattedArray));
// or asign a value
let foramttedArray = formatArray(unformattedArray);

Categories