array_count_values for JavaScript instead - javascript

I have the following PHP-script, now I need to do the same thing in JavaScript. Is there a function in JavaScript that works similar to the PHP function, I have been searching for days but cannot find anything similar? What I want to do is to count the number of times a certain word is being used in an array.
$interfaceA = array($interfaceA_1,$interfaceA_2,$interfaceA_3,$interfaceA_4,$interfaceA_5,$interfaceA_6,$interfaceA_7,$interfaceA_8);
$interfaceA_array=array_count_values($interfaceA);
$knappsatsA = $interfaceA_array[gui_knappsats];
$touchpanelA = $interfaceA_array[gui_touchpanel];

Why not simply create a new javascript array "counts"
Iterate over original array, and increament the count of "counts" for keys encountered in the array.
http://jsfiddle.net/4t28P/1/
var myCurrentArray = new Array("apple","banana","apple","orange","banana","apple");
var counts = {};
for(var i=0;i< myCurrentArray.length;i++)
{
var key = myCurrentArray[i];
counts[key] = (counts[key])? counts[key] + 1 : 1 ;
}
alert(counts['apple']);
alert(counts['banana']);

Another elegant solution would be to use Array.prototype.reduce.
Given:
var arr = new Array("apple","banana","apple","orange","banana","apple");
You can just run reduce on it:
var groups =
arr.reduce(function(acc,e){acc[e] = (e in acc ? acc[e]+1 : 1); return acc}, {});
Finally you can check the result:
groups['apple'];
groups['banana'];
In the sample above reduce takes two parameters:
a function (anonymous here) taking an accumulator (initialized from the second argument of reduce), and the current array element
the initial value of the accumulator
Whatever the function returns, it will be used as the accumulator value in the next call.
From a type perspective, whatever the type of the array elements, the type of the accumulator must match the type of the second argument of reduce (initial value), and the type of the return value of the anonymous function.
This will also be the type of the return value of reduce.

Try
a.reduce((a,c)=> (a[c]=++a[c]||1,a) ,{});
let a= ["apple","banana","apple","orange","banana","apple"];
let count= a.reduce((a,c)=> (a[c]=++a[c]||1,a) ,{});
console.log(count);

How about this:
function arrayCountValues (arr) {
var v, freqs = {};
// for each v in the array increment the frequency count in the table
for (var i = arr.length; i--; ) {
v = arr[i];
if (freqs[v]) freqs[v] += 1;
else freqs[v] = 1;
}
// return the frequency table
return freqs;
}

let snippet = "HARRY POTTER IS A SERIES OF FANTASY NOVELS WRITTEN BY BRITISH AUTHOR J. K. ROWLING. THE NOVELS CHRONICLE" +
" THE LIVES OF A YOUNG WIZARD, HARRY POTTER , AND HIS FRIENDS HERMIONE GRANGER AND RON WEASLEY, ALL OF WHOM ARE " +
" STUDENTS AT HOGWARTS SCHOOL OF WITCHCRAFT AND WIZARDRY";
String.prototype.groupByWord = function () {
let group = {};
this.split(" ").forEach(word => {
if (group[word]) {
group[word] = group[word] + 1;
} else {
group[word] = 1;
}
});
return group;
};
let groupOfWordsByCount = snippet.groupByWord();
console.log(JSON.stringify(groupOfWordsByCount,null, 4))

This should work
function array_count_values(array) {
var tmpArr = {};
var key = '';
var t = '';
var _countValue = function(tmpArr, value) {
if (typeof value === 'number') {
if (Math.floor(value) !== value) {
return;
}
} else if (typeof value !== 'string') {
return;
}
if (value in tmpArr && tmpArr.hasOwnProperty(value)) {
++tmpArr[value];
} else {
tmpArr[value] = 1;
}
}
for (key in array) {
if (array.hasOwnProperty(key)) {
_countValue.call(this, tmpArr, array[key]);
}
}
return tmpArr;
}
console.log(array_count_values([12, 43, 12, 43, "null", "null"]));

Related

How to check how many times character from string appears?

I want to count how many times each letter from params appears in this string. What am I doing wrong?
function solution(word) {
let temp = {}
for(const c of word) {
temp[c]++;
console.log(temp[c])
}
}
solution("PAPAYA")
It should output me numbers below for each letter, but i keep getting NaN
1 // P appeared once
1 // A appeared once
2 // P appeared second time
2 // A appeaed second time
1 // Y Once
3 // A appeared third time
so it should look like
{
A: 3,
P: 2,
Y: 1
}
Here is an easy solution without changing your code to much
function solution(word) {
let temp = {}
for(const c of word) {
if (temp[c] === undefined)
temp[c] = 1;
else temp[c]++;
}
console.log(temp)
}
solution("PAPAYA")
At the start, no properties are set on the object, so accessing the value for a character results in undefined. Incrementing that produces NaN. You will need to specifically handle that case for the first time a letter appears.
function solution(word) {
let temp = {}
for(const c of word)
temp[c] = (temp[c] || 0) + 1;
return temp;
}
console.log(solution("PAPAYA"));
Easy solution using short-circuit in javascript:
function solution(word) {
let temp = {}
for(const c of word) {
temp[c] = temp[c]+1 || 1;
}
console.log(temp);
}
solution("PAPAYA")
The issue with your solution is that the first time the value is undefined so you were increasing undefined by 1, that's why you were getting NaN (Not A Number).
short-circuit will solve that, if it is not defined, start counting from one
set temp[c] to a number (0) first
for example
if (NaN(temp[c])) temp[c] = 0
The reason for this is because if you do ++ on undefined, it is still undefined, and therefore, not a number
const solution = (str) => {
const result = {}
str.split('').forEach(letter => {
result[letter] = result[letter] ? result[letter] + 1 : 1
})
return result
}
console.log(solution("PAPAYA"))
Simplest solution
function solution(word) {
let temp = {}
for(const c of word) {
if(c in temp)
temp[c]++;
else temp[c] = 1;
}
}
solution("PAPAYA")
Solution
let counter = str => {
return str.split('').reduce((total, letter) => {
total[letter] ? total[letter]++ : total[letter] = 1;
return total;
}, {});
};
console.log(counter("PAPAYA"));
//count
let unordered = counter("PAPAYA");
//sort the count object
const ordered = Object.keys(unordered).sort().reduce(
(obj, key) => {
obj[key] = unordered[key];
return obj;
},
{}
);
console.log(ordered);
function solution(word) {
let charMap = {};
word.split("").forEach((eachChar) => {
if (!charMap[eachChar]) {
charMap[eachChar] = 1;
} else {
charMap[eachChar] += 1;
}
});
console.log(charMap);
return charMap;
}
solution("ppiiyaaallll");

Solving a Permutations problem with Heap's Algorithm in Javascript

I'm working through some "Kata's" on CodeWars.com, and am stuck on the Permutations problem.
Here is the problem: n this kata you have to create all permutations
of an input string and remove duplicates, if present. This means, you
have to shuffle all letters from the input in all possible orders.
Examples:
permutations('a'); // ['a']
permutations('ab'); // ['ab', 'ba']
permutations('aabb'); // ['aabb', 'abab', 'abba', 'baab', 'baba', 'bbaa']
The order of the permutations doesn't matter.
Here is my solution:
function permutations(string) {
const swap = (string, x, y) => {
const stringArray = string.split('')
const swapVar = stringArray[x]
stringArray[x] = stringArray[y]
stringArray[y] = swapVar
return stringArray.join('')
}
const permutate = (k, arr) => {
if (k === 1) {
return arr
} else {
for (let i = 0; i < k - 1; i++) {
if (k % 2 === 0) {
arr.push(swap(string, i, k-1))
} else {
arr.push(swap(string, 0, k-1))
}
}
permutate(k - 1, arr)
}
}
return permutate(string.length, [string])
}
When you pass in a single letter, it works fine. Two letters and it returns undefined. I've console logged the if statement block with the return and it should be returning the correct answer, but the result is still undefined. Considering it's getting the correct answer in the if statement and isn't progressing into the else block, I'm at a loss for why this isn't working.
Thank you in advance!
I figured it out - I was missing the return statement before the recursive function call.
Here is a basic solution
String.prototype.replaceAt = function(index, replacement) {
return this.substr(0, index) + replacement + this.substr(index +
replacement.length);}
var words = [];
var string = "lyes";
for(var i = 0;i< string.length;i++){
for(var j = 0;j<string.length;j++){
var tempChar;
if(i!==j){
tempChar = string[j]
var str = string.replaceAt(j,string[i])
str = str.replaceAt(i,tempChar)
if(!words.includes(str)){
words.push(str)
console.log(str)
}
}
}
}
console.log(words.length +" words found")

Alibaba interview: print a sentence with min spaces

I saw this interview question and gave a go. I got stuck. The interview question is:
Given a string
var s = "ilikealibaba";
and a dictionary
var d = ["i", "like", "ali", "liba", "baba", "alibaba"];
try to give the s with min space
The output may be
i like alibaba (2 spaces)
i like ali baba (3 spaces)
but pick no.1
I have some code, but got stuck in the printing.
If you have better way to do this question, let me know.
function isStartSub(part, s) {
var condi = s.startsWith(part);
return condi;
}
function getRestStr(part, s) {
var len = part.length;
var len1 = s.length;
var out = s.substring(len, len1);
return out;
}
function recPrint(arr) {
if(arr.length == 0) {
return '';
} else {
var str = arr.pop();
return str + recPrint(arr);
}
}
// NOTE: have trouble to print
// Or if you have better ways to do this interview question, please let me know
function myPrint(arr) {
return recPrint(arr);
}
function getMinArr(arr) {
var min = Number.MAX_SAFE_INTEGER;
var index = 0;
for(var i=0; i<arr.length; i++) {
var sub = arr[i];
if(sub.length < min) {
min = sub.length;
index = i;
} else {
}
}
return arr[index];
}
function rec(s, d, buf) {
// Base
if(s.length == 0) {
return;
} else {
}
for(var i=0; i<d.length; i++) {
var subBuf = [];
// baba
var part = d[i];
var condi = isStartSub(part, s);
if(condi) {
// rest string
var restStr = getRestStr(part, s);
rec(restStr, d, subBuf);
subBuf.unshift(part);
buf.unshift(subBuf);
} else {
}
} // end loop
}
function myfunc(s, d) {
var buf = [];
rec(s, d, buf);
console.log('-- test --');
console.dir(buf, {depth:null});
return myPrint(buf);
}
// Output will be
// 1. i like alibaba (with 2 spaces)
// 2. i like ali baba (with 3 spaces)
// we pick no.1, as it needs less spaces
var s = "ilikealibaba";
var d = ["i", "like", "ali", "liba", "baba", "alibaba"];
var out = myfunc(s, d);
console.log(out);
Basically, my output is, not sure how to print it....
[ [ 'i', [ 'like', [ 'alibaba' ], [ 'ali', [ 'baba' ] ] ] ] ]
This problem is best suited for a dynamic programming approach. The subproblem is, "what is the best way to create a prefix of s". Then, for a given prefix of s, we consider all words that match the end of the prefix, and choose the best one using the results from the earlier prefixes.
Here is an implementation:
var s = "ilikealibaba";
var arr = ["i", "like", "ali", "liba", "baba", "alibaba"];
var dp = []; // dp[i] is the optimal solution for s.substring(0, i)
dp.push("");
for (var i = 1; i <= s.length; i++) {
var best = null; // the best way so far for s.substring(0, i)
for (var j = 0; j < arr.length; j++) {
var word = arr[j];
// consider all words that appear at the end of the prefix
if (!s.substring(0, i).endsWith(word))
continue;
if (word.length == i) {
best = word; // using single word is optimal
break;
}
var prev = dp[i - word.length];
if (prev === null)
continue; // s.substring(i - word.length) can't be made at all
if (best === null || prev.length + word.length + 1 < best.length)
best = prev + " " + word;
}
dp.push(best);
}
console.log(dp[s.length]);
pkpnd's answer is along the right track. But word dictionaries tend to be quite large sets, and iterating over the entire dictionary at every character of the string is going to be inefficient. (Also, saving the entire sequence for each dp cell may consume a large amount of space.) Rather, we can frame the question, as we iterate over the string, as: given all the previous indexes of the string that had dictionary matches extending back (either to the start or to another match), which one is both a dictionary match when we include the current character, and has a smaller length in total. Generally:
f(i) = min(
f(j) + length(i - j) + (1 if j is after the start of the string)
)
for all j < i, where string[j] ended a dictionary match
and string[j+1..i] is in the dictionary
Since we only add another j when there is a match and a new match can only extend back to a previous match or to the start of the string, our data structure could be an array of tuples, (best index this match extends back to, total length up to here). We add another tuple if the current character can extend a dictionary match back to another record we already have. We can also optimize by exiting early from the backwards search once the matched substring would be greater than the longest word in the dictionary, and building the substring to compare against the dictionary as we iterate backwards.
JavaScript code:
function f(str, dict){
let m = [[-1, -1, -1]];
for (let i=0; i<str.length; i++){
let best = [null, null, Infinity];
let substr = '';
let _i = i;
for (let j=m.length-1; j>=0; j--){
let [idx, _j, _total] = m[j];
substr = str.substr(idx + 1, _i - idx) + substr;
_i = idx;
if (dict.has(substr)){
let total = _total + 1 + i - idx;
if (total < best[2])
best = [i, j, total];
}
}
if (best[0] !== null)
m.push(best);
}
return m;
}
var s = "ilikealibaba";
var d = new Set(["i", "like", "ali", "liba", "baba", "alibaba"]);
console.log(JSON.stringify(f(s,d)));
We can track back our result:
[[-1,-1,-1],[0,0,1],[4,1,6],[7,2,10],[11,2,14]]
[11, 2, 14] means a total length of 14,
where the previous index in m is 2 and the right index
of the substr is 11
=> follow it back to m[2] = [4, 1, 6]
this substr ended at index 4 (which means the
first was "alibaba"), and followed m[1]
=> [0, 0, 1], means this substr ended at index 1
so the previous one was "like"
And there you have it: "i like alibaba"
As you're asked to find a shortest answer probably Breadth-First Search would be a possible solution. Or you could look into A* Search.
Here is working example with A* (cause it's less bring to do than BFS :)), basically just copied from Wikipedia article. All the "turning string into a graph" magick happens in the getNeighbors function
https://jsfiddle.net/yLeps4v5/4/
var str = 'ilikealibaba'
var dictionary = ['i', 'like', 'ali', 'baba', 'alibaba']
var START = -1
var FINISH = str.length - 1
// Returns all the positions in the string that we can "jump" to from position i
function getNeighbors(i) {
const matchingWords = dictionary.filter(word => str.slice(i + 1, i + 1 + word.length) == word)
return matchingWords.map(word => i + word.length)
}
function aStar(start, goal) {
// The set of nodes already evaluated
const closedSet = {};
// The set of currently discovered nodes that are not evaluated yet.
// Initially, only the start node is known.
const openSet = [start];
// For each node, which node it can most efficiently be reached from.
// If a node can be reached from many nodes, cameFrom will eventually contain the
// most efficient previous step.
var cameFrom = {};
// For each node, the cost of getting from the start node to that node.
const gScore = dictionary.reduce((acc, word) => { acc[word] = Infinity; return acc }, {})
// The cost of going from start to start is zero.
gScore[start] = 0
while (openSet.length > 0) {
var current = openSet.shift()
if (current == goal) {
return reconstruct_path(cameFrom, current)
}
closedSet[current] = true;
getNeighbors(current).forEach(neighbor => {
if (closedSet[neighbor]) {
return // Ignore the neighbor which is already evaluated.
}
if (openSet.indexOf(neighbor) == -1) { // Discover a new node
openSet.push(neighbor)
}
// The distance from start to a neighbor
var tentative_gScore = gScore[current] + 1
if (tentative_gScore >= gScore[neighbor]) {
return // This is not a better path.
}
// This path is the best until now. Record it!
cameFrom[neighbor] = current
gScore[neighbor] = tentative_gScore
})
}
throw new Error('path not found')
}
function reconstruct_path(cameFrom, current) {
var answer = [];
while (cameFrom[current] || cameFrom[current] == 0) {
answer.push(str.slice(cameFrom[current] + 1, current + 1))
current = cameFrom[current];
}
return answer.reverse()
}
console.log(aStar(START, FINISH));
You could collect all possible combinations of the string by checking the starting string and render then the result.
If more than one result has the minimum length, all results are taken.
It might not work for extrema with string who just contains the same base string, like 'abcabc' and 'abc'. In this case I suggest to use the shortest string and update any part result by iterating for finding longer strings and replace if possible.
function getWords(string, array = []) {
words
.filter(w => string.startsWith(w))
.forEach(s => {
var rest = string.slice(s.length),
temp = array.concat(s);
if (rest) {
getWords(rest, temp);
} else {
result.push(temp);
}
});
}
var string = "ilikealibaba",
words = ["i", "like", "ali", "liba", "baba", "alibaba"],
result = [];
getWords(string);
console.log('all possible combinations:', result);
console.log('result:', result.reduce((r, a) => {
if (!r || r[0].length > a.length) {
return [a];
}
if (r[0].length === a.length) {
r.push(a);
}
return r;
}, undefined))
Use trie data structure
Construct a trie data structure based on the dictionary data
Search the sentence for all possible slices and build a solution tree
Deep traverse the solution tree and sort the final combinations
const sentence = 'ilikealibaba';
const words = ['i', 'like', 'ali', 'liba', 'baba', 'alibaba',];
class TrieNode {
constructor() { }
set(a) {
this[a] = this[a] || new TrieNode();
return this[a];
}
search(word, marks, depth = 1) {
word = Array.isArray(word) ? word : word.split('');
const a = word.shift();
if (this[a]) {
if (this[a]._) {
marks.push(depth);
}
this[a].search(word, marks, depth + 1);
} else {
return 0;
}
}
}
TrieNode.createTree = words => {
const root = new TrieNode();
words.forEach(word => {
let currentNode = root;
for (let i = 0; i < word.length; i++) {
currentNode = currentNode.set(word[i]);
}
currentNode.set('_');
});
return root;
};
const t = TrieNode.createTree(words);
function searchSentence(sentence) {
const marks = [];
t.search(sentence, marks);
const ret = {};
marks.map(mark => {
ret[mark] = searchSentence(sentence.slice(mark));
});
return ret;
}
const solutionTree = searchSentence(sentence);
function deepTraverse(tree, sentence, targetLen = sentence.length) {
const stack = [];
const sum = () => stack.reduce((acc, mark) => acc + mark, 0);
const ret = [];
(function traverse(tree) {
const keys = Object.keys(tree);
keys.forEach(key => {
stack.push(+key);
if (sum() === targetLen) {
const result = [];
let tempStr = sentence;
stack.forEach(mark => {
result.push(tempStr.slice(0, mark));
tempStr = tempStr.slice(mark);
});
ret.push(result);
}
if(tree[key]) {
traverse(tree[key]);
}
stack.pop();
});
})(tree);
return ret;
}
const solutions = deepTraverse(solutionTree, sentence);
solutions.sort((s1, s2) => s1.length - s2.length).forEach((s, i) => {
console.log(`${i + 1}. ${s.join(' ')} (${s.length - 1} spaces)`);
});
console.log('pick no.1');

How do I make Array.indexOf() case insensitive?

I am making a piece of code for a website that will have a list of names in an array and pick a random name, I want to add a feature that will let the user add or delete a name from the array. I have all of these features but when deleting a name, the user has to type the name to match the Case in the array. I tried to make the so it would be Case-Insensitive, what am I doing wrong?
<html>
<!--Other code uneeded for this question-->
<p id="canidates"></p>
<body>
<input type="text" id="delname" /><button onclick="delName()">Remove Name from List</button>
<script>
//Array of names
var names = [];
//Other code uneeded for this question
//List of Canidates
document.getElementById('canidates').innerHTML =
"<strong>List of Canidates:</strong> " + names.join(" | ");
//Other code uneeded for this question
//Remove name from Array
function delName() {
var dnameVal = document.getElementById('delname').value;
var pos = names.indexOf(dnameVal);
var namepos = names[pos]
var posstr = namepos.toUpperCase();
var dup = dnameVal.toUpperCase();
if(dup != posstr) {
alert("Not a valid name");
}
else {
names.splice(pos, 1);
document.getElementById('canidates').innerHTML =
"<strong>List of Canidates:</strong> " + names.join(" | ");
}
}
</script>
</body>
</html>
ES2015 findIndex:
var array = ['I', 'hAve', 'theSe', 'ITEMs'],
indexOf = (arr, q) => arr.findIndex(item => q.toLowerCase() === item.toLowerCase());
console.log( indexOf(array, 'i') ) // 0
console.log( indexOf(array, 'these') ) // 2
console.log( indexOf(array, 'items') ) // 3
In ECMA-262, 5th edition, you could use Array.prototype.some for this.
var array = [ 'I', 'hAve', 'theSe', 'ITEMs' ];
var query = 'these'.toLowerCase();
var index = -1;
array.some(function(element, i) {
if (query === element.toLowerCase()) {
index = i;
return true;
}
});
// Result: index = 2
Easy way would be to have a temporary array that contains all the names in uppercase. Then you can compare the user input. So your code could become somthing like this:
function delName() {
var dnameVal = document.getElementById('delname').value;
var upperCaseNames = names.map(function(value) {
return value.toUpperCase();
});
var pos = upperCaseNames.indexOf(dnameVal.toUpperCase());
if(pos === -1) {
alert("Not a valid name");
}
else {
names.splice(pos, 1);
document.getElementById('canidates').innerHTML =
"<strong>List of Canidates:</strong> " + names.join(" | ");
}
}
Hope this helps solve your problem.
The most elegant solution would be to convert the array into a string first, then do a case insensitive comparison. For example:
var needle = "PearS"
var haystack = ["Apple", "banNnas", "pEArs"];
var stricmp = haystack.toString().toLowerCase(); // returns
// "apple,bananas,pears"
if (stricmp.indexOf(needle.toLowerCase()) > -1) {
// the search term was found in the array
} else {
// the search term was not found in the array
}
Probably best to create your own custom indexOf method, something like this.
'use strict';
var customIndexOf = function(arrayLike, searchElement) {
var object = Object(arrayLike);
var length = object.length >>> 0;
var fromIndex = arguments.length > 2 ? arguments[2] >> 0 : 0;
if (length < 1 || typeof searchElement !== 'string' || fromIndex >= length) {
return -1;
}
if (fromIndex < 0) {
fromIndex = Math.max(length - Math.abs(fromIndex), 0);
}
var search = searchElement.toLowerCase();
for (var index = fromIndex; index < length; index += 1) {
if (index in object) {
var item = object[index];
if (typeof item === 'string' && search === item.toLowerCase()) {
return index;
}
}
}
return -1;
};
var names = [
'John',
'Anne',
'Brian'
];
console.log(customIndexOf(names, 'aNnE'));
Or even
'use strict';
var customIndexOf = function(array, searchElement, fromIndex) {
return array.map(function(value) {
return value.toLowerCase();
}).indexOf(searchElement.toLowerCase(), fromIndex);
};
var names = [
'John',
'Anne',
'Brian'
];
console.log(customIndexOf(names, 'aNnE'));
You may also want to add more checks to be sure that each element in the array is actually a String and that the searchElement is also actually a String too. If pre-ES5 then load appropriate shims
You can use Array.prototype.find()
found = myArray.find(key => key.toUpperCase() === searchString.toUpperCase()) != undefined;
Example:
myArray = ['An', 'aRRay', 'oF', 'StringS'];
searchString = 'array';
found = myArray.find(key => key.toUpperCase() === searchString.toUpperCase()) != undefined;
if (found ) {
// The array contains the search string
}
else {
// Search string not found
}
Note: Array cannot contain undefined as a value.
It is possible using by map method. For example see below code
var _name = ['prasho','abraham','sam','anna']
var _list = [{name:'prasho'},{name:'Gorge'}];
for(var i=0;i<_list.length;i++)
{
if(_name.map(function (c) {
return c.toLowerCase();
}).indexOf(_list[i].name.toLowerCase()) != -1) {
//do what ever
}else{
//do what ever
}
}
More info
I needed something similar to this where I needed compare two strings using includes and needed to be able to support both case and case insensitive searches so I wrote the following small function
function compare(l1: string, l2: string, ignoreCase = true): boolean {
return (ignoreCase ? l1.toLowerCase() : l1).includes((ignoreCase ? l2.toLowerCase() : l2));
}
Same principle could apply to indexOf as below
function indexOf(l1: string, l2: string, ignoreCase = true): number {
return (ignoreCase ? l1.toLowerCase() : l1).indexOf((ignoreCase ? l2.toLowerCase() : l2));
}
I know this is not specifically Array.indexOf but hope this helps someone out if the come across this post on their travels.
To answer the ops question though, you can apply this similarly to an array combined with this answer from #ULIT JAIDEE (the slight change to this was using the tilda character as a separator in case any of the array values contained spaces)
function compare(l1: any[], l2: any[], ignoreCase = true): boolean {
return (ignoreCase ? l1.join('~').toLowerCase().split('~') : l1).indexOf((ignoreCase ? l2.join('~').toLowerCase().split('~') : l2));
}
Again hope this helps.
Turn the array into a string separated by a delimiter, turn that string lowercase, and then split the string back into an array by the same delimiter:
function findIt(arr, find, del) {
if (!del) { del = '_//_'; }
arr = arr.join(del).toLowerCase().split(del);
return arr.indexOf(find.toLowerCase());
}
var arr = ['Tom Riddle', 'Ron Weasley', 'Harry Potter', 'Hermione Granger'];
var find = 'HaRrY PoTtEr';
var index = findIt(arr, find);
if (~index) {
alert('Found ' + arr[index] + '! :D');
} else {
alert('Did not find it. D:');
}
This is the shortest one.
haystack.join(' ').toLowerCase().split(' ').indexOf(needle.toLowerCase())
// unique only, removes latter occurrences
array.filter((v, i, a) => a.findIndex(j => v.toLowerCase() === j.toLowerCase()) === i);
To improve on #vsync answer and handle mixed content in the array here is my take. (I understand the OP is about case-sensitive thus it implies strings, maybe :)
var array = ['I', 'hAve', 7, {}, 'theSe', 'ITEMs'],
Contains = (arr, q) =>
arr.findIndex((item) => q.toString().toLowerCase() === item.toString().toLowerCase());
console.log(Contains(array, 'i'));
console.log(Contains(array, 'x'));
console.log(Contains(array, {} ));
console.log(Contains(array, 7 ));
You can't make it case-insensitive. I'd use an object instead to hold a set of names:
function Names() {
this.names = {};
this.getKey = function(name) {
return name.toLowerCase();
}
this.add = function(name) {
this.names[this.getKey(name)] = name;
}
this.remove = function(name) {
var key = this.getKey(name);
if (key in this.names) {
delete this.names[key];
} else {
throw Error('Name does not exist');
}
}
this.toString = function() {
var names = [];
for (var key in this.names) {
names.push(this.names[key]);
}
return names.join(' | ');
}
}
var names = new Names();
function update() {
document.getElementById('canidates').innerHTML = '<strong>List of Canidates:</strong> ' + names;
}
function deleteName() {
var name = document.getElementById('delname').value;
try {
names.remove(name);
update();
} catch {
alert('Not a valid name');
}
}
update();

Removing duplicates and summing up quantity

var name = new Array();
var amount = new Array();
name[0]="Peter";
amount[0]="50";
name[1]="John";
amount[1]="10";
name[2]="John";
amount[2]="20";
name[3]="Peter";
amount[3]="20";
name[4]="Mary";
amount[4]="40";
I have something like the above. My question is, how can I create a function to eliminate all the duplicates and sum up the values for each person in the arrays? Below is the results I am looking for.
For example:
Peter 70
John 30
Mary 40
Try the following
var sum = {};
var i;
for (i = 0; i < amount.length; i++) {
var name = name[i];
var oldSum = sum[name];
if (typeof oldSum === 'undefined') {
oldSum = 0;
}
sum[name] = oldSum + amount[i];
}
Now the object sum will have a property for every name in name and the value of the property will be the sum of the amounts which had the that name
To print it out try the following
for (var prop in sum) {
if (sum.hasOwnProperty(prop)) {
console.log(prop + " " sum[prop]);
}
}
result = {};
for( var i=name.length; i--; ) {
result[name[i]] = result[ name[i] ] ? (result[name[i]] + parseInt( amount[i], 10 )) : parseInt( amount[i], 10 );
}
console.log( result );
returns
{ Mary=40, Peter=70, John=30 }
The parseInt() is just necessary as you give the amount[] values as strings.
result after the call is an object holding the summed up values, where the key is the entry from name[] and the value is from amount[].
tally=[];
for(i=0;i<name.length;i++) {
if(tally[name[i]]==undefined){
tally[name[i]]=parseInt(amount[i]);
}else{
tally[name[i]]+=parseInt(amount[i]);
}
}
I can't tell if you actually want to modify the Arrays, or just collect the results.
Here's a way to collect the results in an Object.
var result = name.reduce(function(res, n, i) {
res[n] = (res[n] + +amount[i]) || +amount[i];
return res;
}, {});
The .reduce() method requires a shim for IE8 and lower.
Result is:
{
"Peter": 70,
"John": 30,
"Mary": 40
}

Categories

Resources