Rename multiple same occurrences in array - javascript

I have an array of titles (sentences). Some of these titles repeat in this whole array, so for example my array is (shortened titles for clarity):
var arr = ['a','b', 'c', 'a', 'f', 'r', 'b', 'a'];
As you can see some values repeat more than once. I need to rename multiple occurrences by appending the counter (starting from 1) to the first matching occurrence.
So in the end I must have:
'a', 'a1', 'a2', 'b', 'b1'
which means I need to have counter stored for every of the repeating occurrence.
How could I write this in javascript/jquery?

Here's some pseudocode, wherein tally is a title-count mapping (e.g. {title:0}):
for (var i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) != i) {
tally[arr[i]]++;
arr[i] = arr[i] + tally[arr[i]];
}
}

Language agnostic algorithm
Add the elements of array to map so that no duplicate elements would be present and initialize it to 0.
Iterate through array
Check if the elemnt is present in map
if present then
map[element]++;
element+value of element at map+1;
else element
Example:
var arr = ['a','b', 'c', 'a', 'f', 'r', 'b', 'a'];
//initialize the map
map m
m[a]=0; m[b]=0; m[c]=0; m[f]=0; m[r]=0;
for(index=0 to size of array){
if(m[arr[index]]){
m[arr[index]]++;
write arr[index] with m[arr[index]];
}else{
write arr[index];
}
}
You could use maps as mentioned here How to create a simple map using JavaScript/JQuery and then I think everything is almost same.

Related

is splice 3rd parameter iaccepting any value?

I can't figure out why newArr is not changing. Seems like my splice function isnt accepting "first13[index]" as argument. Though, when i change "index" to a fixed value, everything worck. I indeed consoleloged index, and it shows correct values as integer. Im really confused here. Any tips?
function rot13(str) {
let first13 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm'];
let second13 = ['n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
let newArr = str.toLowerCase().split('');
let index = 0;
for (let i=0; i<newArr.length; i++) {
if(first13.indexOf(newArr[i]) != -1) {
index = first13.indexOf(newArr[i]);
newArr.splice(i, 1, first13[index]);
console.log(newArr);
}
}
}
rot13("EBG13 rknzcyr.") // "ROT13 example.";
The code's working fine.
There is a mistake in your logic.
You are just replacing the element with the same.
For example you are replacing E with first13(index) which is E.
May be change first13[index] to second13[index] if you want to replace it with +13 characters.
EDIT: The above change must be made for parameter of splice() method.
Everything is working exactly as it's coded as...
Dry running your code:
iteration 1:
index=0
i=0
if( first13.indexOf("e") != -1 ) //true
{
index = first13.indexOf("e") //index = 4
newArr.splice(0,1,first13[4]) //at 0th index remove one element and add first13[4] therefore newArr[0] becomes "e" from "e" (basically remains same)
console.log(newArray) . //printing the array which is same as before.
}
iteration 2:
index=4 //from last iteration
i=1
if( first13.indexOf("b") != -1 ) //true
{
index = first13.indexOf("e") //index = 1
newArr.splice(1,1,first13[1]) //at 1st index remove one element and add first13[1] therefore newArr[1] becomes "b" from "b" (basically remains same)
console.log(newArray) //printing the array which is same as before.
}
After every iteration the array is same since you're replacing elements with same element, as seen above. Re write the logic. You haven't coded what you wanted to do...
With the current setup, the code is just replacing letters in newArr with the same letter from first13.
When the code runs through the first time,
index = first13.indexOf(newArr[i]);
is setting index = 4, then
newArr.splice(i, 1, first13[index]);
is taking the letter at first13[4], 'e' in this case, and replacing newArr[0], which also happens to already be 'e'.
As Raj Datta Manohar suggested above, change the last property in your splice method to second13[index] and you should get something closer to what you're looking for.
Everyone here has already answered how to correct the logic in your code. Below is just another way to approach the problem that might help in reading the logic because there's a little less going on.
function rot13(str) {
let input = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
let output = 'NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm';
let index = (x) => input.indexOf(x);
let translate = (x) => index(x) > -1 ? output[index(x)] : x;
console.log(str.split('').map(translate).join(''));
}
rot13("EBG13 rknzcyr."); // ROT13 example.

Javascript: How to delete specific character values within strings within an array

I am trying to remove punctuation from each string within an array, but this problem would exist for trying to delete any type of character within strings within an array.
I have attempted to create 3 loops:
The first loop iterates over each item in arrayA that I'm aiming to edit.
The second loop iterates through each character in each string in arrayA.
The third loop checks whether the character in arrayA matches any character in arrayB, and deletes it if it does.
Nothing is being deleted however, and I'm not sure why.
This is my code so far:
let arrayA = ['abc', 'def', 'ghi'];
let arrayB = ['a', 'e', 'i', 'o', 'u'];
arrayA.forEach((item) => {
for (let i=0; i < item.length; i++) {
for (let arrayBIndex = 0; arrayBIndex < arrayB.length; arrayBIndex++) {
item.replace(arrayB[arrayBIndex], '');
};
};
});
console.log(arrayA);
I have searched for other questions dealing with this, but I haven't been able to find any answers, specifically where the elements to delete are contained in another list. Thank you for your help.
You can generate regular expression using arrayB and then using array#map iterate through each word in arrayA and use string#replace to get rid of words from arrayB.
let arrayA = ['abc', 'def', 'ghi'],
arrayB = ['a', 'e', 'i', 'o', 'u'],
regExp = new RegExp(arrayB.join('|'), 'g'),
result = arrayA.map(word => word.replace(regExp, ''));
console.log(result);
Use Array.prototype.splice(), take a look on this:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice
If you wish to follow with arrays, I would suggest to transform your strings into an array of characters and using array filter operator.
However you can probably achieve what you want to do with regular expressions
const arrayA = ['abc', 'def', 'ghi'];
const arrayB = ['a', 'e', 'i', 'o', 'u'];
const result = arrayA
.map(s => [...s]) // array of chars
.map(chars => chars.filter(ch=>!arrayB.includes(ch)).join(''))//filter out invalid char and transform back into string
console.log(result)
const result = arrayA.map(item => {
let replaced = "";
for(const char of item)
if(!arrayB.includes(char))
replaced += char;
return replaced;
});
Strings are immutable. Every mutation returns a new string instead of mutating the original.

Push and remove duplicates of array

I have an array (or Set?) of arr = ['a', 'b', 'c'] and I want to add d to it, which could be done with arr.push('d').
But I only want unique values in the array, and I want the latest values added to be in the front of the array.
So if I first add d the array should become ['d', 'a', 'b', 'c'] and if I now add b the array should become ['b', 'd', 'a', 'c'] etc.
Should it be something like
function addElement(arr, element) {
if (arr.includes(element)) {
arr.splice(arr.indexOf(element, 1));
}
arr.unshift(element);
}
I guess this could be done with Sets, since sets can only contain unique values.
You could use a Set and delete the item in advance and add it then. To get the wanted order, you need to reverse the rendered array.
function addToSet(v, set) {
set.delete(v);
set.add(v);
}
var set = new Set;
addToSet('d', set);
addToSet('c', set);
addToSet('b', set),
addToSet('a', set);
addToSet('d', set);
console.log([...set].reverse());
var val = 'c';
var arr = ['a','b'];
if($.inArray( val, arr ) ==-1){
// value dosend exit
arr.unshift(val);
} else {
console.log('value already there')
}
console.log(arr);
$.inArray() work similar to indexOf() method. It searches the element in an array, if it’s found then it return it’s index.
http://webrewrite.com/check-value-exist-array-javascriptjquery/
your function works just you have to adjust with a small fix
arr.splice(arr.indexOf(element),1);
var arr = ['a', 'b', 'c'] ;
function addElement(arr, element) {
if (arr.includes(element)) {
arr.splice(arr.indexOf(element),1);
}
arr.unshift(element);
}
addElement(arr,'d');
addElement(arr,'b');
console.log(arr);
Especially for those who don't like .unshift() performance This would be another way of doing this job;
function funky(a,e){
var ix = a.indexOf(e);
return (~ix ? a.splice(ix,0,...a.splice(0,ix))
: a.splice(0,0,e),a);
}
var a = ['d', 'a', 'b', 'c'];
console.log(funky(a,'z'));
console.log(funky(a,'d'));
console.log(funky(a,'c'));
console.log(funky(a,'f'));

How to get the even and odd entries from an array with Ramda

I have the following:
var isEven = function (n) { return n % 2 === 0; }
var isOdd = function (n) { return n % 2 !== 0; }
var indexedList = function(fn, list) {
var array = [];
for (var i = 0; i < list.length; i++) {
if (fn(i)) {
array.push(list[i]);
}
}
return array;
}
Is there a Ramda equivalent of IndexedList so I can have an array of just the even index based elements and an array of odd based index elements.
Ramda's list-based functions by default do not deal with indices. This, in part, is because many of them are more generic and also work with other data structures where indices don't make sense. But there is a standard mechanism for altering functions so that they do pass the indices of your lists along: addIndex.
So my first thought on this is to first of all, take your isEven and extend it to
var indexEven = (val, idx) => isEven(idx);
Then you can use addIndex with filter and reject like this:
R.addIndex(R.filter)(indexEven, ['a', 'b', 'c', 'd', 'e']);
//=> ['a', 'c', 'e']
R.addIndex(R.reject)(indexEven, ['a', 'b', 'c', 'd', 'e']);
//=> ['b', 'd']
Or if you want them both at once, you can use it with partition like this:
R.addIndex(R.partition)(indexEven, ['a', 'b', 'c', 'd', 'e']);
//=> [["a", "c", "e"], ["b", "d"]]
You can see this in action, if you like, on the Ramda REPL.
If the list length is even, I would go with
R.pluck(0, R.splitEvery(2, ['a','b','c']))
The disadvantage of this is that it will give undefined as a last element, when list length is odd and we want to select with offset 1 ( R.pluck(1) ). The advantage is that you can easily select every nth with any offset while offset < n.
If you can't live with this undefined than there is another solution that I find more satisfying than accepted answer, as it doesn't require defining a custom function. It won't partition it nicely though, as the accepted answer does.
For even:
R.chain(R.head, R.splitEvery(2, ['a','b','c','d']))
For odd:
R.chain(R.last, R.splitEvery(2, ['a','b','c','d']))
As of Ramda 0.25.0, the accepted solution will not work. Use this:
const splitEvenOdd = R.compose(R.values, R.addIndex(R.groupBy)((val,idx) => idx % 2))
splitEvenOdd(['a','b','c','d','e'])
// => [ [ 'a', 'c', 'e' ], [ 'b', 'd' ] ]

Remove array elements and add them back to where they were

I am trying to remove elements from arrays while remembering their position and add them back later. So far I have this piece of code:
var my_array = ['A', 'B', 'C', 'D', 'E'];
var removed_elements = [];
// Assuming letter provided exists in my_array
function remove_element(letter) {
for (var index in my_array) {
if (my_array[index] == letter) {
break;
}
}
var removed_element = {
index: index,
letter: letter
}
removed_elements.push(removed_element);
my_array.splice(index,1);
}
// Assuming letter provided exists in removed_elements
function add_element(letter) {
for (var index in removed_elements) {
console.log('test');
if (removed_elements[index].letter == letter) {
console.log(removed_elements[index]);
break;
}
}
my_array.splice(removed_elements[index].index,0,removed_elements[index].letter);
}
It works fine as long as I remove 1 element at a time and add it back before removing another one. However, when I start removing several elements consecutively, the index saved for removed elements (not first one, but subsequent ones) becomes relative to the state of my_array at the time of removal, and not absolute to my_array's initial state, which can cause problems.
For instance if you remove 'B' and 'D' and add 'D' and 'B', you end up with ['A', 'B', 'C', 'E', 'D'] instead of ['A', 'B', 'C', 'D', 'E'].
Here is a jsfiddle showing what the problem is
What modifications should I change for my_array to end up in its initial state no matter of many elements I remove or add and how?
I thought about storing information about which elements surround the removed element at the time of removal and use that as extra info when adding back but wondering if there is a better way.
I wouldn't actually remove them at all:
var my_array = ['A', 'B', 'C', 'D', 'E'];
var removed = [];
function remove_element(letter) {
var i = my_array.indexOf(letter);
if(i > -1) {
removed.push(i);
}
}
function add_element(letter) {
var i = my_array.indexOf(letter);
if(i > -1) {
removed.splice(removed.indexOf(i), 1);
}
}
function get_array() {
return my_array.filter(function(x, i) {
return removed.indexOf(i) === -1;
});
}

Categories

Resources