trying to find the best way to check for triplicates values inside an array of strings.
I found many stackoverflow solutions for duplicates values which is not the case in here.
This is the farest i could get with solving this and I am not sure if it is the correct way:
const array = [
"peace",
"peace",
"Vrede",
"Patz",
"Salam",
"paz",
"Salam",
"Salam"
];
const findTriplicates = (param) => {
let counts = {};
for (let i = 0; i < param.length; i++) {
if (counts[param[i]]) {
counts[param[i]] += 1;
} else {
counts[param[i]] = 1;
}
}
for (let i in counts) {
if (counts[i] === 3) {
console.log(i + " exists " + counts[i] + " times.");
}
}
};
findTriplicates(array); // Salam exists 3 times.
please don't hesitate to fix my code or to post your solution.
thanks for your support in advance :)
Cheerz!
Your overall idea is good, using Hash Maps (js objects) is the best option for the task.
You can move your "=== 3" check to the first loop and have another object to save triplicates, it will be twice faster.
check this out
const findTriplicates = (param) => {
let values = [...new Set(param)];
let triples = [];
values.forEach(item=>{
let counter = 0;
param.forEach(s=>{
if(s===item) counter++;
})
if(3==counter) triples.push(item);
})
return triples;
};
There is no correct way to do things like this. You can always optimize or sacrifice performance for readability, but that is up to the developer.
I changed nothing about the functionality in findTriplicates, but the code is very different.
findTriplicates2 works a little different but is by no means superior
const array = [
"peace",
"peace",
"Vrede",
"Patz",
"Salam",
"paz",
"Salam",
"Salam"
];
const findTriplicates = (param) => {
let counts = param.reduce((acc, p) => {
acc[p] ? acc[p]++ : acc[p] = 1
return acc;
}, {})
Object.keys(counts).forEach((key) => counts[key] === 3 &&
console.log(`${key} exists 3 times.`)
);
};
findTriplicates(array); // Salam exists 3 times.
const findTriplicates2 = (param) => {
let triples = [...new Set(param)].reduce((acc, item) => {
let counter = param.reduce((acc2, s) => {
if (s === item) acc2++;
return acc2;
}, 0);
if (3 == counter) acc.push(item);
return acc;
}, [])
triples.forEach((triple) => console.log(`${triple} exists 3 times.`));
};
findTriplicates2(array); // Salam exists 3 times.
You create an object to keep count of how many times the string repeats and then iterate through each element in the array while updating the count in the object. Then you filter through that object for any values equal to 3.
const array = [
'peace',
'peace',
'Vrede',
'Patz',
'Salam',
'paz',
'Salam',
'Salam',
];
// Object to keep count of each word
const countObj = {};
// Iterate through the array to get the count for each word
array.forEach((element) => {
// Does word exist in the count object? if so -> add 1 to its count, else -> add word and count 1 to the object
countObj[element] ? (countObj[element] += 1) : (countObj[element] = 1);
});
// Filter out keys that appear exactly 3 times and print them them
const filteredArray = Object.keys(countObj).filter(
(key) => countObj[key] === 3
);
console.log(filteredArray); // Salam
Related
I have a array of string.
let arr=["robin","rohit","roy"];
Need to find all the common character present in all the strings in array.
Output Eg: r,o
I have tried to create a function for above case with multiple loops but i want to know what should be the efficient way to achive it.
Here's a functional solution which will work with an array of any iterable value (not just strings), and uses object identity comparison for value equality:
function findCommon (iterA, iterB) {
const common = new Set();
const uniqueB = new Set(iterB);
for (const value of iterA) if (uniqueB.has(value)) common.add(value);
return common;
}
function findAllCommon (arrayOfIter) {
if (arrayOfIter.length === 0) return [];
let common = new Set(arrayOfIter[0]);
for (let i = 1; i < arrayOfIter.length; i += 1) {
common = findCommon(common, arrayOfIter[i]);
}
return [...common];
}
const arr = ['robin', 'rohit', 'roy'];
const result = findAllCommon(arr);
console.log(result);
const arr = ["roooooobin","rohit","roy"];
const commonChars = (arr) => {
const charsCount = arr.reduce((sum, word) => {
const wordChars = word.split('').reduce((ws, c) => {
ws[c] = 1;
return ws;
}, {});
Object.keys(wordChars).forEach((c) => {
sum[c] = (sum[c] || 0) + 1;
});
return sum;
}, {});
return Object.keys(charsCount).filter(key => charsCount[key] === arr.length);
}
console.log(commonChars(arr));
Okay, the idea is to count the amount of times each letter occurs but only counting 1 letter per string
let arr=["robin","rohit","roy"];
function commonLetter(array){
var count={} //object used for counting letters total
for(let i=0;i<array.length;i++){
//looping through the array
const cache={} //same letters only counted once here
for(let j=0;j<array[i].length;j++){
//looping through the string
let letter=array[i][j]
if(cache[letter]!==true){
//if letter not yet counted in this string
cache[letter]=true //well now it is counted in this string
count[letter]=(count[letter]||0)+1
//I don't say count[letter]++ because count[letter] may not be defined yet, hence (count[letter]||0)
}
}
}
return Object.keys(count)
.filter(letter=>count[letter]===array.length)
.join(',')
}
//usage
console.log(commonLetter(arr))
No matter which way you choose, you will still need to count all characters, you cannot get around O(n*2) as far as I know.
arr=["robin","rohit","roy"];
let commonChars = sumCommonCharacters(arr);
function sumCommonCharacters(arr) {
data = {};
for(let i = 0; i < arr.length; i++) {
for(let char in arr[i]) {
let key = arr[i][char];
data[key] = (data[key] != null) ? data[key]+1 : 1;
}
}
return data;
}
console.log(commonChars);
Here is a 1 liner if anyone interested
new Set(arr.map(d => [...d]).flat(Infinity).reduce((ac,d) => {(new RegExp(`(?:.*${d}.*){${arr.length}}`)).test(arr) && ac.push(d); return ac},[])) //{r,o}
You can use an object to check for the occurrences of each character. loop on the words in the array, then loop on the chars of each word.
let arr = ["robin","rohit","roy"];
const restWords = arr.slice(1);
const result = arr[0].split('').filter(char =>
restWords.every(word => word.includes(char)))
const uniqueChars = Array.from(new Set(result));
console.log(uniqueChars);
I have two arrays. One is a smaller array of environments, the other is a larger, nested array that contains a list of adjectives for each environment. The arrays correspond to one another by index. I would like to create a function that takes in the environment as an argument and returns the longest adjective that describes that environment.
The function I've created returns ONLY the longest word in the entire adjectives array, not the longest adjective unique to a given environment.
I want to create a function called "longestAdjective" that takes in one of the environments and returns ONLY the longest adjective corresponding to that environment from the list of adjectives.
environmentsArray = ["Desert", "Rainforest", "Mountains", "Plains"]
adjectives = [["dry", "hot", "scorching"], ["humid", "shady",
"wet"], ["cool", "chilly", "windy"], ["flat", "reaching", "sunny"]]
let longAdjective = (environment) => {
let longAdj = ""
let length = 0;
for (let i = 0; i < adjectives.length; i++) {
for (let j = 0; j < adjectives[i].length; j++) {
if (adjectives[i][j].length > length) {
length = adjectives[i][j].length;
longAdj = adjectives[i][j];
}
}
}
return longAdj
}
I don't have any error messages because I'm trying to recreate the function I've already made. I'm not sure exactly where to start.
You can iterate over the relevant subarray, finding the longest within that. The code you current have iterates over all the subarrays, which isn't what you want.
const environmentsArray = ["Desert", "Rainforest", "Mountains", "Plains"];
const adjectives = [["dry", "hot", "scorching"], ["humid", "shady",
"wet"], ["cool", "chilly", "windy"], ["flat", "reaching", "sunny"]];
const longAdjective = (environment) => {
let longAdj = ""
let length = 0;
const envIndex = environmentsArray.indexOf(environment);
if (envIndex === -1) {
return;
}
for (const adj of adjectives[environmentsArray.indexOf(environment)]) {
if (adj.length > length) {
length = adj.length;
longAdj = adj;
}
}
return longAdj;
}
console.log(longAdjective('Desert'));
something like that ?
const environmentsArray = ["Desert", "Rainforest", "Mountains", "Plains"]
, adjectives = [ ["dry", "hot", "scorching"]
, ["humid", "shady", "wet"]
, ["cool", "chilly", "windy"]
, ["flat", "reaching", "sunny"]
]
const LongestAdjective = environment =>
{
let idx = environmentsArray.findIndex(e=>e===environment)
if (idx<0) return null
return adjectives[idx].reduce((a,c)=>((a.length<c.length)?c:a))
}
console.log( 'Rainforest :', LongestAdjective('Rainforest') )
console.log( 'Plains :', LongestAdjective('Plains') )
You can use the reduce function to get the longest adjective from the adjectives array based on the environment entry choosed :
const environmentsArray = ['Desert', 'Rainforest', 'Mountains', 'Plains'],
adjectives = [
['dry', 'hot', 'scorching'],
['humid', 'shady', 'wet'],
['cool', 'chilly', 'windy'],
['flat', 'reaching', 'sunny']
],
longestAdjective = (env) => {
return adjectives[environmentsArray.indexOf(env)].reduce((a, b) => {
return a.length > b.length ? a : b
}); /** the callback function does the filtration based on the string length of "a" (current element in the array) and "b" (the next element to check). The callback function is called for every value in the array **/
}
console.log(longestAdjective('Desert')); /** output: "scorching" **/
Learn more about reduce function.
How can I get one unique value in an array or string? Only the first value. Pure JS only.
My example:
function searchValue () {
let inputText = [1,1,4,2,2,2,3,1];
let foundedValue;
for (let i = 0; i < inputText.length; i++) {
if (i === inputText.indexOf(inputText[i]) && i === inputText.lastIndexOf(inputText[i])) {
foundedValue = inputText[i];
break;
} else {
foundedValue = "not founded.";
}
}
return foundedValue;
}
console.log("Search value: "+ searchValue())
Answer is 4.
But, I need a short solution. Using the find() and filter() functions.
You can find the first unique item in your array using find() and comparing indexOf() to lastIndexOf() to determine whether or not there is more than one instance of an item in the array. If you need to find unique characters in a string, then you can first split it into an array and then use the same approach.
const arr = [1, 1, 4, 2, 2, 2, 3, 1];
const result = arr.find((x) => arr.indexOf(x) === arr.lastIndexOf(x));
console.log(result);
// 4
const text = 'aadbbbca';
const textarr = text.split('');
const textresult = textarr.find((x) => textarr.indexOf(x) === textarr.lastIndexOf(x));
console.log(textresult);
// d
You can try this.
const arr = [1, 1, 4, 2, 2, 2, 3, 1];
let r = {};
arr.map(a => r[a] = (r[a] || 0) +1)
var res = arr.find(a => r[a] === 1 )
console.log(res)
You can use js Set() object.
At first you could create a Set of duplicated elements.
const inputText = [1,1,4,2,2,2,3,1];
const duplicatesSet= inputText.reduce((dupSet, el) =>
inputText.filter(arrEl => arrEl === el).length > 1 ?
dupSet.add(el) : dupSet
, new Set());
Second you could use array.find. It returns first duplicated element.
const firstDupElement = inputText.find(el => duplicatesSet.has(el));
const searchValue = (_param) => {
for (let i= 0; i < _param.length; i+= 1) {
if (_param.indexOf(_param[i]) === _param.lastIndexOf(_param[i])) return _param[i];
}
return "not founded.";
}
let arr = [1,1,2,2,2,1,3,1,4,4,5]
const dupelearray = (array) => {
let arr2 =[...arr]
let ele = []
let state = false
arr2.map((i,index)=>{
arr2.splice(index,1)
arr.map((j)=>{
return arr2.includes(j) ? null : state=true
})
state && ele.push(i)
state=false
arr2.splice(index,0,i)
})
return console.log(arr.indexOf(ele[0]))
}
dupelearray(arr)
wow i didnt knew lastindexof method and was making this algo so difficult
btw this solution also works but definitely i am new in algo so this will take much more time but the solution still works!!!!!! damn should remember more methods or you have to think so much -_-
I believe what I need are two JavaScript functions. I am receiving a comma separated string that holds two types of data: 1) device name followed by 2) numeric value. These two values are separated by a comma, and each set is also separated by a comma. Example string below:
Device_A,5,Device_C,2,Device_A,10,Device_B,8,Device_B,2,Device_C,7
What I want to do is create two separate functions. The first function finds the unique device names and returns just the names in a comma separated string. The second function would calculate the sum of the numeric values for each device. The expected results from the example string above would return:
Function 1 (Device List):
Device_A, Device_B, Device_C
Function 2 (Sums per Device List):
15,10,9
The lists do not need to return in any particular order as long at they both match up. All I have successfully done at this point is return a list of unique values (including numeric values)... I'm stuck on separating the list, but still referring to device name to sum up all of the values.
Thanks in advance. Let me know if you have any questions!
Matt
You could use an object for collecting the names and count.
This edit contains a shared function and two function for the result in equal order.
function getGrouped(data) {
var array = data.split(','),
temp = Object.create(null),
i = 0;
while (i < array.length) {
temp[array[i]] = (temp[array[i]] || 0) + +array[i + 1] || 0;
i += 2;
}
return temp;
}
function getDevices(data) {
var temp = getGrouped(data);
return Object.keys(temp).sort().join();
}
function getCounts(data) {
var temp = getGrouped(data);
return Object.keys(temp).sort().map(function (k) { return temp[k]; }).join();
}
var data = "Device_A,5,Device_C,2,Device_A,10,Device_B,8,Device_B,2,Device_C,7";
console.log(getDevices(data));
console.log(getCounts(data));
When starting out on a problem like this, I think it's wise to not worry about doing it in a single loop or in a fancy one-liner at first.
A) Start out by defining what data structures you need and how to go from one format to another:
Convert my string of data to a list of keys and values
Somehow group these keys and values based on the key
Sum the values for each group
Return a list of all unique keys
Return a list of all summed values
B) Then, try to see if any of the code you've written has the potential be re-used by other parts of your application and refactor accordingly.
C) Finally, assess if there are performance bottle necks and only if there are, optimize for performance.
A. A function for each step:
// 1. From string to array of keys and values
// You already figured this one out. Split by ","!
const namesAndValuesFromString =
str => str.split(",");
// 2. Grouping by key
// Let's first make pairs:
const deviceValuePairs = devicesAndValues => {
let pair = [];
const pairs = [];
devicesAndValues.forEach(x => {
pair.push(x);
if (pair.length === 2) {
pairs.push(pair);
pair = [];
}
});
return pairs;
};
// Key value pairs are a nice starting point for constructing a grouped object:
const kvpsToDeviceValuesObj = kvps => {
const valuesByDevice = {};
kvps.forEach(([key, value]) => {
value = Number(value);
if (!valuesByDevice[key]) {
valuesByDevice[key] = [];
}
valuesByDevice[key].push(value);
});
return valuesByDevice;
};
// 3. Now, we can get to summing the values arrays
const sumValueArrays = valuesByDevice => {
const summedValuesByDevice = {};
// Loop over the objects entries
Object.entries(valuesByDevice).forEach(
([key, values]) => {
summedValuesByDevice[key] = values
.reduce((a, b) => a + b);
}
);
return summedValuesByDevice;
};
// 4. + 5. Now that we have an object with device ids as keys, and summed values inside, we can retrieve the two lists
const getDevices = Object.keys;
const getSums = Object.values;
// Running the code:
const namesAndValues =
namesAndValuesFromString("A,5,C,2,A,10,B,8,B,2,C,7");
console.log(namesAndValues);
const kvps = deviceValuePairs(namesAndValues);
console.log(kvps);
const valuesByDevice = kvpsToDeviceValuesObj(kvps);
console.log(valuesByDevice);
const sumValues = sumValueArrays(valuesByDevice);
console.log(sumValues);
const devices = getDevices(sumValues);
console.log(devices);
const sums = getSums(sumValues);
console.log(sums);
B. Refactoring!
Once you understand each of those steps, you'll start to see things that can be generalized or combined. That's where the fun starts :)
// UTILITIES
const split = del => arr => arr.split(del);
const toPairs = arr => {
let pair = [];
return arr.reduce(
(pairs, x) => {
pair.push(x);
if (pair.length === 2) {
pairs.push(pair);
pair = [];
}
return pairs;
}, []);
};
const sum = (x, y = 0) => +x + y;
const kvpsToGroups = grouper => kvps =>
kvps.reduce(
(groups, [key, value]) => Object.assign(groups, {
[key]: grouper(value, groups[key])
}), {});
// YOUR APP
const sumGrouper = kvpsToGroups(sum);
const dataSplitter = split(",");
const parseData = str => sumGrouper(toPairs(dataSplitter(str)));
// MAIN
const result = parseData("A,5,C,2,A,10,B,8,B,2,C,7");
console.log("devices:", Object.keys(result));
console.log("sums:", Object.values(result));
another way by regexs
let str = "Device_A,5,Device_C,2,Device_A,10,Device_B,8,Device_B,2,Device_C,7", obj = {}
str.match(/(\w+,[0-9]+)/g).forEach((s) => {
s = s.split(',')
obj[s[0]] = (obj[s[0]] || 0) + (Number(s[1]) || 0)
})
console.log(obj)
Something like this should do it:
var input = "Device_A,5,Device_C,2,Device_A,10,Device_B,8,Device_B,2,Device_C,7";
var output = input.split(',').reduce((accumulator, currentValue, currentIndex, array) => {
accumulator[currentValue] = (accumulator[currentValue] || 0)
+ parseInt(array[currentIndex + 1]);
array.splice(0,1);
return accumulator;
}, {});
console.log(Object.keys(output));
console.log(Object.keys(output).map(k => output[k]));
This question already has answers here:
How can I access and process nested objects, arrays, or JSON?
(31 answers)
Closed 6 years ago.
I have a JavaScript array:
var j_array = new Array();
j_arry=["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
I need to find how many times the class is coming and its array key, so I use:
found = $.inArray('class', j_array); ` But it returns `-1`;
Then I use:
var search = 'class';
$.each([j_array], function(index, value){
$.each(value, function(key, cell){
if (search.indexOf(cell) !== -1)
console.log('found in array '+index, cell);
});
});
But that is also wrong. How do I solve this?
From this array I want to get the following:
Class coming 4 times, at key 0, 2, 3, and 7
I want to make a separate array of class only, that is,
new_array = ["class:1", "class:2", "class:3", "class:10"];
Currently there are four classes in j_array. How can I get the Nth class value
That is, 1st class value ="class:1", 2nd class value="class:5", etc.
You could filter elements which match in a new array and just return the length of this new array
var j_arry = ["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
var res = j_arry.filter(x => x.includes("class"));
var key = res.map(x => x.split(":")[1]);
console.log("Class coming " + res.length + " , at key " + key.join(","));
console.log("new array = ", res);
Use Array.prototype.filter to filter out the elements of the array that contains the string class - see demo below:
var j_array =["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
var result = j_array.filter(function(e){
return e.indexOf('class')!==-1;
});
console.log(result);
EDIT:
To get the list of indexes too, you can try this:
var j_array =["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"];
var filteredIndices = []
var filtered = j_array.filter(function(e,i){
if(e.indexOf('class')!==-1) {
filteredIndices.push(i);
return true;
} else {
return false;
}
});
console.log(filtered);
console.log(filteredIndices);
// Nth class value
console.log(filtered[2]); // this prints the 3rd one
.as-console-wrapper{top:0;max-height:100%!important;}
Here is the answer to your questions 1 + 2. It is also 'n' proof so answers your part 3 also. This works by old-fashioned hard graft rather than funky functions. The original array entries are split and filtered then if qualifying we store in an associative array (results) using a pointer array (list) to make it easier to give a sorted result and pull the values from the associative array. The max variable is probably not necessary but included for clarity - could have used list.length instead. Note that the list[] array will be sparse (missing steps) so we test each entry before use in the output steps.
var j_array = new Array();
j_arry=["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10","class:1"];
var a, result = [], list=[], max = -1
for (var i =0; i < j_arry.length; i = i + 1) {
var a = j_arry[i].split(":")
if ( a[0] === "class") {
var key = "c" + a[1]
if ( !result[key] ) { result[key] = {pos:[]}}
result[key].cnt = result[key].cnt ? result[key].cnt + 1 : 1;
result[key].pos.push(i)
list[parseInt(a[1])] = "c" + a[1]
max = parseInt(a[1]) > max ? a[1] : max;
}
}
// say locations
for (var i = 0; i < max; i = i + 1) {
if (list[i]) {
key = "c" + i
console.log("Class " + i + " occurs at " + result[key].pos.toString() )
}
}
// make new array
var newArray=[]
for (var i = 0; i < max; i = i + 1) {
if (list[i]) {
newArray.push("Class:" + i)
}
}
console.log("New array=" + newArray.toString() )
Results are:
Class 1 occurs at 0,8
Class 3 occurs at 3
Class 5 occurs at 2
New array=Class:1,Class:3,Class:5
Single reduce is sufficient here.
var arr = ["class:1","division:a","class:5","class:3","division:b","division:c","division:d","class:10"],
res = arr.reduce((p,c) => c.includes("class") ? (p.count++, p.keys.push(c.split(":")[1]), p)
: p ,{count:0, keys:[]});
console.log(res);
You can use the filter and map functions to filter your array to have only elements that match the text 'class', and use array index notation to access the nth element in the array. Check the below code snippet I hope it will be of help to you.
The below code snippet uses ES6 arrow syntax.
var arr = ["class:1", "division:a", "class:5", "class:3", "division:b", "division:c", "division:d", "class:10"];
var result = arr.filter(x => x.indexOf('class') !== -1);
var indices = result.map(x => arr.indexOf(x));
console.log(indices);
console.log(result);
var nValue = window.prompt('Enter n value');
console.log(result[nValue]);
If you're using jQuery to support some really old browser that still don't implement the new Array functions, and you don't want to polyfill those because you're already using jQuery, then you can use the jQuery equivalents:
var arr = ["class:1", "division:a", "class:5", "class:3", "division:b", "division:c", "division:d", "class:10"]
var result = $.grep(arr, function (x) { return x.indexOf('class') !== -1 })
var indices = $.map(result, function (x) { return arr.indexOf(x) })
This is the same code as this answer, but using jQuery.
You have to do map first then filter.
var j_array = ["class:1", "division:a", "class:5", "class:3", "division:b", "division:c", "division:d", "class:10"];
var result = j_array.map(function(e, i) {
return e.indexOf('class') > -1 ? '' + i : false;
}).filter(function(e) {
return !!e;
});
console.log(result);