How to collapse an array by joining all strings, but leaving objects - javascript

While I'm sure I'm waay over-complicating things, I'm curious to know how I would "collapse" an array by combining all adjacent strings, but leaving objects as objects so that:
array = ["I","want","to",[Obj],"come","together"]
outputs
["I want to", [Obj], "come together"];
I feel like array.reduce() might be the ticket here, but I'm still wrapping my head around that function.

Reduce the array. If the current item and the last item in the accumulator (r) are strings, concatenate them. If not, push the current item to the accumulator:
const array = ["I","want","to",[{}],"come","together"]
const isString = s => typeof s === 'string'
const result = array.reduce((r, o) => {
if(isString(o) && isString(r[r.length - 1])) {
r[r.length - 1] = `${r[r.length - 1]} ${o}`
} else {
r.push(o)
}
return r
}, [])
console.log(result)

I would do this:
const array = ["I","want","to",{},"come","together"];
let outputArr = [];
let strArr = [];
array.forEach(elem => {
if (typeof elem === 'string') {
return strArr.push(elem);
}
outputArr.push(strArr.join(' '));
strArr = [];
outputArr.push(elem);
});
outputArr.push(strArr.join(' '));
console.log(outputArr);

In case you wanna go with the plain old for-loop :)
var result = [], array = ["I","want","to",{a: 1, b:2},"come","together"];
var i=0;var str = "";
for(; i< array.length; i++){
if(typeof array[i] === 'object' ){
result.push(str);
result.push(array[i]);
str="";
}else{
str = str+" "+ array[i];
}
}
if(i==array.length){
result.push(str);
}
console.log(result);

Related

Information about to Array in JAvascript

I would like to get find elements having same characters but in different order in an array. I made javascript below,is there any way to create Javascript function more basic? Can you give me an idea? Thank you in advance..
<p id="demo"></p>
<script>
const arr1 = ["tap", "pat", "apt", "cih", "hac", "ach"];
var sameChars = 0;
var subArr1 = [];
for(var i = 0; i < arr1.length; i++){
for(var j = i+1; j < arr1.length; j++){
if(!subArr1.includes(arr1[i]) && !subArr1.includes(sortAlphabets(arr1[i]))){
subArr1.push(arr1[i]);
sameChars++;
}
if(sortAlphabets(arr1[i]) == sortAlphabets(arr1[j])){
if(!subArr1.includes(arr1[j])){
subArr1.push(arr1[j]);
}
}
}
}
function sortAlphabets(text1) {
return text1.split('').sort().join('');
};
document.getElementById("demo").innerHTML = sameChars;
</script>
I would just use reduce. Loop over split the string, sort it, join it back. Use it as a key in an object with an array and push the items onto it.
const arr1 = ["tap", "pat", "apt", "cih", "hac", "ach"];
const results = arr1.reduce((obj, str) => {
const key = str.split('').sort().join('');
obj[key] = obj[key] || [];
obj[key].push(str);
return obj;
}, {});
console.log(Object.values(results));
You can get the max frequency value by building a map and getting the max value of the values.
const frequencyMap = (data, keyFn) =>
data.reduce(
(acc, val) =>
(key => acc.set(key, (acc.get(key) ?? 0) + 1))
(keyFn(val)),
new Map());
const groupMap = (data, keyFn) =>
data.reduce(
(acc, val) =>
(key => acc.set(key, [...(acc.get(key) ?? []), val]))
(keyFn(val)),
new Map());
const
data = ["tap", "pat", "apt", "cih", "hac", "ach"],
sorted = (text) => text.split('').sort().join(''),
freq = frequencyMap(data, sorted),
max = Math.max(...freq.values()),
groups = groupMap(data, sorted);
document.getElementById('demo').textContent = max;
console.log(Object.fromEntries(freq.entries()));
console.log(Object.fromEntries(groups.entries()));
.as-console-wrapper { top: 2em; max-height: 100% !important; }
<div id="demo"></div>
Maybe split the code into two functions - one to do the sorting and return a new array, and another to take that array and return an object with totals.
const arr = ['tap', 'pat', 'apt', 'cih', 'hac', 'ach'];
// `sorter` takes an array of strings
// splits each string into an array, sorts it
// and then returns the joined string
function sorter(arr) {
return arr.map(str => {
return [...str].sort().join('');
});
}
// `checker` declares an object and
// loops over the array that `sorter` returned
// creating keys from the strings if they don't already
// exist on the object, and then incrementing their value
function checker(arr) {
const obj = {};
for (const str of arr) {
// All this line says is if the key
// already exists, keep it, and add 1 to the value
// otherwise initialise it with 0, and then add 1
obj[str] = (obj[str] || 0) + 1;
}
return obj;
}
// Call `checker` with the array from `sorter`
console.log(checker(sorter(arr)));
<p id="demo"></p>
Additional documentation
map
Loops and iteration
Spread syntax

Delete all occurrence of duplicate values in an array in javascript/jquery

I am trying to work on a problem where I want to remove all the occurrences of similar value in an array
eg.
var sampleArr = ["mary","jane","spiderman","jane","peter"];
and I am trying to get result as => ["marry","spiderman","peter"]
how do I get this?
You can use filter()
var arr = ["mary","jane","spiderman","jane","peter"];
var unique = arr.filter((x, i) => arr.indexOf(x) === i);
console.log(unique);
var sampleArr = ["mary","jane","spiderman","jane","peter"];
var unique = [];
var itemCount = {};
sampleArr.forEach((item,index)=>{
if(!itemCount[item]){
itemCount[item] = 1;
}
else{
itemCount[item]++;
}
});
for(var prop in itemCount){
if(itemCount[prop]==1){
unique.push(prop);
}
}
console.log(unique);
Check this.
You can count the frequency of the character and just pick the character whose frequency is 1.
const arr = ["mary","jane","spiderman","jane","peter"];
frequency = arr.reduce((o,ch) => {
o[ch] = (o[ch] || 0) + 1;
return o;
}, {}),
unique = Object.keys(frequency).reduce((r,k) => frequency[k] === 1? [...r, k]: r, []);
console.log(unique);
You can use filter:
var sampleArr = ["mary","jane","spiderman","jane","peter"];
var result = sampleArr.filter((e,_,s)=>s.filter(o=>o==e).length<2);
// or with reduce and flatmap
const result1 = Object.entries(sampleArr.reduce((a,e)=>(a[e]??=0, a[e]++, a),{})).flatMap(([k,v])=>v==1 ? k: []);
console.log(result)
console.log(result1);
lot of solution, here easy solution to understand using match to have the occurence and filter to eliminate:
var arr = ['ab','pq','mn','ab','mn','ab'];
var st = arr.join(",");
result = arr.filter(it => {
let reg = new RegExp(it, 'g');
return st.match(reg).length == 1;
});
console.log(result);// here ["pq"]
filter seems to be your best bet here if you need extremely robust performance. No real need for jQuery in this instance. Personally, I would opt for readability for something like this and instead sort, set duplicates to null, and then remove all null values.
var sampleArr = ["mary","jane","spiderman","jane","peter"];
var result = sampleArr.sort().forEach((value, index, arr) => {
// if the next one is the same value,
// set this one to null
if(value === arr[value + 1])
return arr[index] = null;
// if the previous one is null, and the next one is different,
// this is the last duplicate in a series, so should be set to null
if(arr[value - 1] === arr[index + 1] !== value)
return arr[index] = null;
return
})
.filter(value => value === null) //remove all null values
console.log(result);

Delete the previous and next element from an array while using array.map() in javascript

How can I delete the previous and next element from an array while using array.map();
In the code below, when I get to 'crossover' I want to delete both 'SUV' and 'sedan'.
The following code deletes 'sedan' and 'truck' instead of 'sedan' and 'SUV' ;
let arr = ['excavator','SUV','crossover','sedan','truck'] ;
arr = arr.map((ele,ind,ar) => {
if (ele === 'crossover'){
ar.splice(ind+1,1);
ar.splice(ind-1,1);
}
return ele + ": Sold.";
});
return arr; //it produces ['excavator: Sold.','SUV: Sold.','crossover: Sold.',,]
You can first remove the elements and then map the array, here is an example:
let arr = ['excavator','SUV','crossover','sedan','truck'];
arr.splice(arr.indexOf('crossover') - 1, 3, 'crossover');
arr = arr.map((ele) => {
return ele + ": Sold.";
});
console.log(arr);
The .splice(..) call replaces SUV, crossover and sedan with crossover
You should not remove elements on a .map interation since the array size will change as well as the array indexes.
You should try something like this:
let arr = ['excavator','SUV','crossover','sedan','truck'] ;
arr = arr.filter(element => element != "crossover");
arr = arr.map(ele => `${ele} :Sold.`);
console.log(arr);
Or, from an old school perspective:
let arr = ['excavator','SUV','crossover','sedan','truck'];
let newArr=[]
for (var i=0; i<arr.length; i++)
if(arr[i] !== 'crossover')
newArr.push(`${arr[i]} :Sold.`)
console.log(newArr);
itus has the correct anwer, IMO but for the sake of fun this is an alternative way:
let arr = ['excavator','SUV','crossover','sedan','truck'] ;
let suvIndex = null;
const result = arr.map((item, index) => {
if (item === "SUV") {
suvIndex = index;
}
if(suvIndex && index <= suvIndex + 2) {
return null;
}
return item;
}).filter(chunk => chunk)
console.log(result);
https://jsfiddle.net/vbz14fw6/

How to remove same value if it has in an array? [duplicate]

Let's assume that I have ;
var array = [1,2,3,4,4,5,5];
I want it to be;
var newArray = [1,2,3];
I want to remove the duplicates completely rather than keeping them as unique values. Is there a way achieve that through reduce method ?
You could use Array#filter with Array#indexOf and Array#lastIndexOf and return only the values which share the same index.
var array = [1, 2, 3, 4, 4, 5, 5],
result = array.filter(function (v, _, a) {
return a.indexOf(v) === a.lastIndexOf(v);
});
console.log(result);
Another approach by taking a Map and set the value to false, if a key has been seen before. Then filter the array by taking the value of the map.
var array = [1, 2, 3, 4, 4, 5, 5],
result = array.filter(
Map.prototype.get,
array.reduce((m, v) => m.set(v, !m.has(v)), new Map)
);
console.log(result);
I guess it won't have some remarkable performance, but I like the idea.
var array = [1,2,3,4,4,5,5],
res = array.reduce(function(s,a) {
if (array.filter(v => v !== a).length == array.length-1) {
s.push(a);
}
return s;
}, []);
console.log(res);
Another option is to use an object to track how many times an element is used. This will destroy the array order, but it should be much faster on very large arrays.
function nukeDuplications(arr) {
const hash = {};
arr.forEach(el => {
const qty = hash[el] || 0;
hash[el] = qty+1;
});
const ret = [];
Object.keys(hash).forEach(key => {
if (hash[key] === 1) {
ret.push(Number(key));
}
})
return ret;
}
var array = [1,2,3,4,4,5,5];
console.log(nukeDuplications(array));
A slightly more efficient solution would be to loop over the array 1 time and count the number of occurrences in each value and store them in an object using .reduce() and then loop over the array again with .filter() to only return items that occurred 1 time.
This method will also preserve the order of the array, as it merely uses the object keys as references - it does not iterate over them.
var array = [1,2,3,4,4,5,5];
var valueCounts = array.reduce((result, item) => {
if (!result[item]) {
result[item] = 0;
}
result[item]++;
return result;
}, {});
var unique = array.filter(function (elem) {
return !valueCounts[elem] || valueCounts[elem] <= 1;
});
console.log(unique)
Another option is to use an object to track how many times an element is used. This will destroy the array order, but it should be much faster on very large arrays.
// Both versions destroy array order.
// ES6 version
function nukeDuplications(arr) {
"use strict";
const hash = {};
arr.forEach(el => {
const qty = hash[el] || 0;
hash[el] = qty + 1;
});
const ret = [];
Object.keys(hash).forEach(key => {
if (hash[key] === 1) {
ret.push(Number(key));
}
})
return ret;
}
// ES5 version
function nukeDuplicationsEs5(arr) {
"use strict";
var hash = {};
for (var i = 0; i < arr.length; i++) {
var el = arr[i];
var qty = hash[el] || 0;
hash[el] = qty + 1;
};
var ret = [];
for (let key in hash) {
if (hash.hasOwnProperty(key)) {
if (hash[key] === 1) {
ret.push(Number(key));
}
}
}
return ret;
}
var array = [1, 2, 3, 4, 4, 5, 5];
console.log(nukeDuplications(array));
console.log(nukeDuplicationsEs5(array));
There are a lot of over-complicated, and slow running code here. Here's my solution:
let numbers = [1,2,3,4,4,4,4,5,5]
let filtered = []
numbers.map((n) => {
if(numbers.indexOf(n) === numbers.lastIndexOf(n)) // If only 1 instance of n
filtered.push(n)
})
console.log(filtered)
you can use this function:
function isUniqueInArray(array, value) {
let counter = 0;
for (let index = 0; index < array.length; index++) {
if (array[index] === value) {
counter++;
}
}
if (counter === 0) {
return null;
}
return counter === 1 ? true : false;
}
const array = [1,2,3,4,4,5,5];
let uniqueValues = [];
array.forEach(element => {
if(isUniqueInArray(array ,element)){
uniqueValues.push(element);
}
});
console.log(`the unique values is ${uniqueValues}`);
If its help you, you can install the isUniqueInArray function from my package https://www.npmjs.com/package/jotils or directly from bit https://bit.dev/joshk/jotils/is-unique-in-array.
My answer is used map and filter as below:
x = [1,2,3,4,2,3]
x.map(d => x.filter(i => i == d).length < 2 ? d : null).filter(d => d != null)
// [1, 4]
Object.values is supported since ES2017 (Needless to say - not on IE).
The accumulator is an object for which each key is a value, so duplicates are removed as they override the same key.
However, this solution can be risky with misbehaving values (null, undefined etc.), but maybe useful for real life scenarios.
let NukeDeps = (arr) => {
return Object.values(arr.reduce((curr, i) => {
curr[i] = i;
return curr;
}, {}))
}
I would like to answer my questions with an answer I came up with upon reading it again
const array = [1, 2, 3, 4, 4, 5, 5];
const filtered = array.filter(item => {
const { length } = array.filter(currentItem => currentItem === item)
if (length === 1) {
return true;
}
});
console.log(filtered)
//Try with this code
var arr = [1,2, 3,3,4,5,5,5,6,6];
arr = arr.filter( function( item, index, inputArray ) {
return inputArray.indexOf(item) == index;
});
Also look into this link https://fiddle.jshell.net/5hshjxvr/

Completely removing duplicate items from an array

Let's assume that I have ;
var array = [1,2,3,4,4,5,5];
I want it to be;
var newArray = [1,2,3];
I want to remove the duplicates completely rather than keeping them as unique values. Is there a way achieve that through reduce method ?
You could use Array#filter with Array#indexOf and Array#lastIndexOf and return only the values which share the same index.
var array = [1, 2, 3, 4, 4, 5, 5],
result = array.filter(function (v, _, a) {
return a.indexOf(v) === a.lastIndexOf(v);
});
console.log(result);
Another approach by taking a Map and set the value to false, if a key has been seen before. Then filter the array by taking the value of the map.
var array = [1, 2, 3, 4, 4, 5, 5],
result = array.filter(
Map.prototype.get,
array.reduce((m, v) => m.set(v, !m.has(v)), new Map)
);
console.log(result);
I guess it won't have some remarkable performance, but I like the idea.
var array = [1,2,3,4,4,5,5],
res = array.reduce(function(s,a) {
if (array.filter(v => v !== a).length == array.length-1) {
s.push(a);
}
return s;
}, []);
console.log(res);
Another option is to use an object to track how many times an element is used. This will destroy the array order, but it should be much faster on very large arrays.
function nukeDuplications(arr) {
const hash = {};
arr.forEach(el => {
const qty = hash[el] || 0;
hash[el] = qty+1;
});
const ret = [];
Object.keys(hash).forEach(key => {
if (hash[key] === 1) {
ret.push(Number(key));
}
})
return ret;
}
var array = [1,2,3,4,4,5,5];
console.log(nukeDuplications(array));
A slightly more efficient solution would be to loop over the array 1 time and count the number of occurrences in each value and store them in an object using .reduce() and then loop over the array again with .filter() to only return items that occurred 1 time.
This method will also preserve the order of the array, as it merely uses the object keys as references - it does not iterate over them.
var array = [1,2,3,4,4,5,5];
var valueCounts = array.reduce((result, item) => {
if (!result[item]) {
result[item] = 0;
}
result[item]++;
return result;
}, {});
var unique = array.filter(function (elem) {
return !valueCounts[elem] || valueCounts[elem] <= 1;
});
console.log(unique)
Another option is to use an object to track how many times an element is used. This will destroy the array order, but it should be much faster on very large arrays.
// Both versions destroy array order.
// ES6 version
function nukeDuplications(arr) {
"use strict";
const hash = {};
arr.forEach(el => {
const qty = hash[el] || 0;
hash[el] = qty + 1;
});
const ret = [];
Object.keys(hash).forEach(key => {
if (hash[key] === 1) {
ret.push(Number(key));
}
})
return ret;
}
// ES5 version
function nukeDuplicationsEs5(arr) {
"use strict";
var hash = {};
for (var i = 0; i < arr.length; i++) {
var el = arr[i];
var qty = hash[el] || 0;
hash[el] = qty + 1;
};
var ret = [];
for (let key in hash) {
if (hash.hasOwnProperty(key)) {
if (hash[key] === 1) {
ret.push(Number(key));
}
}
}
return ret;
}
var array = [1, 2, 3, 4, 4, 5, 5];
console.log(nukeDuplications(array));
console.log(nukeDuplicationsEs5(array));
There are a lot of over-complicated, and slow running code here. Here's my solution:
let numbers = [1,2,3,4,4,4,4,5,5]
let filtered = []
numbers.map((n) => {
if(numbers.indexOf(n) === numbers.lastIndexOf(n)) // If only 1 instance of n
filtered.push(n)
})
console.log(filtered)
you can use this function:
function isUniqueInArray(array, value) {
let counter = 0;
for (let index = 0; index < array.length; index++) {
if (array[index] === value) {
counter++;
}
}
if (counter === 0) {
return null;
}
return counter === 1 ? true : false;
}
const array = [1,2,3,4,4,5,5];
let uniqueValues = [];
array.forEach(element => {
if(isUniqueInArray(array ,element)){
uniqueValues.push(element);
}
});
console.log(`the unique values is ${uniqueValues}`);
If its help you, you can install the isUniqueInArray function from my package https://www.npmjs.com/package/jotils or directly from bit https://bit.dev/joshk/jotils/is-unique-in-array.
My answer is used map and filter as below:
x = [1,2,3,4,2,3]
x.map(d => x.filter(i => i == d).length < 2 ? d : null).filter(d => d != null)
// [1, 4]
Object.values is supported since ES2017 (Needless to say - not on IE).
The accumulator is an object for which each key is a value, so duplicates are removed as they override the same key.
However, this solution can be risky with misbehaving values (null, undefined etc.), but maybe useful for real life scenarios.
let NukeDeps = (arr) => {
return Object.values(arr.reduce((curr, i) => {
curr[i] = i;
return curr;
}, {}))
}
I would like to answer my questions with an answer I came up with upon reading it again
const array = [1, 2, 3, 4, 4, 5, 5];
const filtered = array.filter(item => {
const { length } = array.filter(currentItem => currentItem === item)
if (length === 1) {
return true;
}
});
console.log(filtered)
//Try with this code
var arr = [1,2, 3,3,4,5,5,5,6,6];
arr = arr.filter( function( item, index, inputArray ) {
return inputArray.indexOf(item) == index;
});
Also look into this link https://fiddle.jshell.net/5hshjxvr/

Categories

Resources