Related
I want to count how often a number in an Array occurs. For example, in Python I can use Collections.Counter to create a dictionary of how frequently an item occurs in a list.
This is as far as I've gotten in JavaScript:
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
/* obj[array[i]] = +=1 */ <= pseudo code
}
How can I create this frequency counter object?
Close but you can't increment undefined so you need to set initial value if it doesn't exist
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = (obj[array[i]] || 0) +1 ;
}
You were almost there. See below code:
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = (obj[array[i]] || 0 ) +1;
}
console.log(obj);
Create an object and check if that specific key exist.If exist then increase it's value by 1
var array = [1, 4, 4, 5, 5, 7];
var obj = {};
for (var i = 0; i < array.length; i++) {
if (obj.hasOwnProperty(array[i])) {
obj[array[i]] += 1;
} else {
obj[array[i]] = 1;
}
}
console.log(obj)
You can use the ? : ternary operator to set initial value as 1 and then increment it on subsequent matches.
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = obj[array[i]]?obj[array[i]]+1:1;
}
console.log(obj);
If the array is always going to be same, and you are going to check frequency of multiple items in the same array without it it being modified, #JohanP's answer is good.
But if you are only going to check frequency of only one item, or the array can change, creating the object is nothing but extra overhead.
In that case, you can do something like this:
const getItemFrequency = function(array, item) {
return array.filter(i => i === item).length;
}
var array = [1,4,4,5,5,7];
console.log(getItemFrequency(array, 4));
Concise logic written as proper function:
function countArrayItemFrequecy(array) {
const length = array.length;
const map = {};
for ( let i = 0; i < length; i++ ) {
let currentItem = array[i];
if (typeof map[currentItem] !== 'undefined' ) {
map[currentItem]++
} else {
map[currentItem] = 1
}
}
return map;
}
You need to make sure to assign default value to your frequency object for the first occurrence of the item. As a shortcut you can use ternary operator
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = obj[array[i]] ? obj[array[i]]++ : 1;
}
which is the same as:
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
if (obj[array[i]]) {
obj[array[i]]++;
} else {
obj[array[i]] = 1;
}
}
You can use Object.assign: below clones map and then increments/adds the counter. These are pure (no side effects/param reassignment), single-purpose functions.
addToMap does the same thing as { ...map, map[e]: [e]: (map[e] || 0) + 1 }, but that requires babel.
const addToMap = (map, e) => Object.assign({}, map, { [e]: (map[e] || 0) + 1 });
const buildMap = a => a.reduce(addToMap, {});
Using Array.reduce:
arr.reduce(function (acc, item) {
acc[item] = (acc[item] || 0) + 1;
return acc;
}, {});
Example:
var arr = [1,1,2,4,1,4];
var counts = arr.reduce(function (acc, item) {
acc[item] = (acc[item] || 0) + 1;
return acc;
}, {});
console.log(counts);
Starting with this initial 2D array:
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
I need to create this 3D array programmatically:
var fullArray = [
[[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]],
[[3,4],[0,1],[5,6],[2,3],[6,7],[3,4]],
[[4,5],[1,2],[6,7],[3,4],[0,1],[4,5]],
[[5,6],[2,3],[0,1],[4,5],[1,2],[5,6]],
[[6,7],[3,4],[1,2],[5,6],[2,3],[6,7]],
[[0,1],[4,5],[2,3],[6,7],[3,4],[0,1]],
[[1,2],[5,6],[3,4],[0,1],[4,5],[1,2]],
[[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]],
[[3,4],[0,1],[5,6],[2,3],[6,7],[3,4]],
[[4,5],[1,2],[6,7],[3,4],[0,1],[4,5]],
[[5,6],[2,3],[0,1],[4,5],[1,2],[5,6]]
];
See the pattern?
On each pair, the [0] position should increment to 6 (from any starting number <= 6) and then reset to 0 and then continue incrementing. Similarly, the [1] position should increment to 7 (from any starting number <= 7) and then reset to 1 and then continue incrementing.
In this example, there are 10 2D arrays contained in the fullArray. However, I need this number to be a variable. Something like this:
var numberOf2DArraysInFullArray = 12;
Furthermore, the initial array should be flexible so that initialArray values can be rearranged like this (but with the same iteration follow-through rules stated above):
var initialArray = [[6,7],[2,3],[5,6],[4,5],[1,2],[6,7]];
Any thoughts on how to programmatically create this structure?
Stumped on how to gracefully pull this off.
Feedback greatly appreciated!
Here's a solution, I've separated the methods, and I made it so if instead of pairs it's an N size array and you want the [2] to increase up to 8 and reset to 2, if that's not needed you can simplify the of the loop for(var j = 0; j < innerArray.length; j++)
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
var create3DArray = function(array, size){
var newArray = [initialArray];
for(var i = 0; i < size; i++)
{
newArray.push(getNextArrayRow(newArray[i]));
}
return newArray;
}
var getNextArrayRow = function(array){
var nextRow = [];
for(var i = 0; i < array.length; i++)
{
var innerArray = array[i];
var nextElement = [];
for(var j = 0; j < innerArray.length; j++)
{
var value = (innerArray[j] + 1) % (7 + j);
value = value === 0 ? j : value;
nextElement.push(value);
}
nextRow.push(nextElement);
}
return nextRow;
}
console.log(create3DArray(initialArray,3));
Note, the results from running the snippet are a bit difficult to read...
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
var numOfArrays = 10;
// get a range array [0, 1, 2, ...]
var range = [];
for (var i = 0; i < numOfArrays; i++) {
range.push(i);
}
var result = range.reduce(function(prev, index) {
if (index == 0) {
return prev;
}
prev.push(transformArray(prev[index - 1]));
return prev;
}, [initialArray])
console.log(result);
function transformArray(arr) {
return arr.map(transformSubArray)
}
function transformSubArray(arr) {
return arr.map(function(val) {
return val == 7 ? 0 : val + 1;
})
}
Here's a pretty simple functional-ish implementation
How can I split the below string into a 2dimensional-array:
Customer::Europe|UK|Scotland|Product::Drinks|Water|
array:
[Customer][Europe]
[Customer][UK]
[Customer][Scotland]
[Product][Drinks]
[Product][Water]
Not sure how to create the array. Haven't coded in years, so be kind
hArray= [];
vArray= [];
var i = j = 0;
var count = hierarchy.search(/[:|]+/);
write(hierarchy);
while (count > 0) {
if (hierarchy.indexOf(":") < hierarchy.indexOf("|") || (hierarchy.indexOf(":") > 0 && hierarchy.indexOf("|") == -1) ) {
hArray[j] = hierarchy.substr(0,hierarchy.indexOf(":"));
hierarchy = hierarchy.slice(hierarchy.indexOf(":")+2);
count = hierarchy.search(/[:|]+/);
j++;
} else
if (hierarchy.indexOf("|") < hierarchy.indexOf(":") {
vArray[i] = hierarchy.substr(0,count);
hierarchy = hierarchy.slice(count+1);
count = hierarchy.search(/[:|]+/);
i++;
}
if (count == -1) break;
//create multiArray ?
}
var source = "Customer::Europe|UK|Scotland|Product::Drinks|Water|";
var parts = source.split(/(\w+::)/);
var result = [];
for (var i = 1; i < parts.length; i += 2) {
var key = parts[i].replace("::", "");
var values = parts[i + 1].split("|");
for (var j = 0; j < values.length - 1; ++j) {
var line = new Array(2);
line[0] = key;
line[1] = values[j];
result.push(line);
}
}
console.log(result);
You can use Array.reduce like this. First, we split on | that is behind any owrd followed by ::. Then we reduce it, by using an array as memo and push an array into the memo, which we finally return.
var arr = input.split(/\|(?=\w+::)/).reduce(function(arr, str){
var array = str.split('::');
return arr.push(str.split('::')[1].split('|').filter(String).map(function(s){
return [array[0], s]
})), arr;
}, []);
Hey i have a simple question i cant find an answer,
i´m trying to generate some raw-data for a chart
lets say i have an array like :
[1,0,0,1,2,0]
is there a way to make an array out of it that has nested arrays that represent the count of duplicate entrys ?
[[0,3],[1,2],[2,1]]
here is some code that does the trick, but saves the count as objects
var array = [1,0,0,1,2,0];
var length = array.length;
var objectCounter = {};
for (i = 0; i < length; i++) {
var currentMemboerOfArrayKey = JSON.stringify(array[i]);
var currentMemboerOfArrayValue = array[i];
if (objectCounter[currentMemboerOfArrayKey] === undefined){
objectCounter[currentMemboerOfArrayKey] = 1;
}else{
objectCounter[currentMemboerOfArrayKey]++;
}
}
but objectCounter returns them like
{0:3,1:2,2:1}
but i need it as an array i specified above ?
for any help, thanks in advance
Try
var array = [1, 0, 0, 1, 2, 0];
function counter(array) {
var counter = [],
map = {}, length = array.length;
$.each(array, function (i, val) {
var arr = map[val];
if (!arr) {
map[val] = arr = [val, 0];
counter.push(arr);
}
arr[1] += 1;
})
return counter;
}
console.log(JSON.stringify(counter(array)))
Demo: Fiddle
You can turn your object into an array easily:
var obj = {0:3,1:2,2:1};
var arr = [];
for (var key in obj) {
// optional check against Object.prototype changes
if (obj.hasOwnProperty(key)) {
arr.push([+key, obj[key]]);
}
}
Note: The object keys are strings, so i converted them back to numbers when placed in the array.
Functional way of doing this, with Array.reduce and Array.map
var data = [1,0,0,1,2,0];
var result = data.reduce(function(counts, current) {
counts[current] = current in counts ? counts[current] + 1: 1;
return counts;
}, {});
result = Object.keys(result).map(function(current){
return [parseInt(current), result[current]];
});
console.log(result);
Output
[ [ 0, 3 ], [ 1, 2 ], [ 2, 1 ] ]
Try:
var data = [1,0,0,1,2,0];
var len = data.length;
var ndata = [];
for(var i=0;i<len;i++){
var count = 0;
for(var j=i+1;j<len;j++){
if(data[i] == data[i]){
count ++;
}
}
var a = [];
a.push(data[i]);
a.push(count);
ndata.push(a);
}
console.log(ndata)
DEMO here.
First you need to map the array to an associative object
var arr = [1,0,0,1,2,0];
var obj = {};
for (var i = 0; i < arr.length; i++) {
if (obj[arr[i]] == undefined) {
obj[arr[i]] = 0;
}
obj[arr[i]] += 1;
}
Then you can easily turn that object into a 2d matrix like so:
arr = [];
for (var k in obj) {
arr.push([k, obj[k]]);
}
alert(JSON.stringify(arr));
Your existing object can be turned into an array with a simple for..in loop. Also your existing code that produces that object can be simplified. Encapsulate both parts in a function and you get something like this:
function countArrayValues(array) {
var counter = {},
result = [];
for (var i = 0, len = array.length; i < len; i++)
if (array[i] in counter)
counter[array[i]]++;
else
counter[array[i]] = 1;
for (i in counter)
result.push([+i, counter[i]]);
return result;
}
console.log( countArrayValues([1,0,0,1,2,0]) );
Demo: http://jsfiddle.net/hxRz2/
Here is one to get your brain going! I've not had any luck with it.
[1,2,1,1,2,1,1,1,2,2]
[1,2,1,1,2,1]
I would like to use the second array to find the values in the first, but they must be in the same order.
Once for I would like it to return the next key up from the last key in the second array.
So in this example it would use the first six digits in the first array and then return 6 as the key after the final one in the second array.
var a2 = [1,2,1,1,2,1,1,1,2,2]
var a1 = [1,2,1,1,0,1]
function find(arr1, arr2) {
var len = 1
var result = 0;
var s2 = arr2.toString();
for (len=1;len <= a1.length; len++)
{
var aa1 = arr1.slice(0, len)
var s1 = aa1.toString();
if(s2.indexOf(s1)>=0){
result = aa1.length;
}
else {
break;
}
}
return result;
}
alert(find(a1, a2));
var find = function(haystack, needle) {
var doesMatch = function(offset) {
for (var i = 0; i < needle.length; i++) {
if (haystack[i+offset] !== needle[i]) {
return false;
}
}
return true;
};
for (var j=0; j < haystack.length - needle.length; j++) {
if (doesMatch(j)) {
return j;
}
}
return -1;
};
This is quick, this is dirty, and this is correct only if your data doesn't include any comma.
var needle = [1,2,1,1,2,1];
var haystack = [1,2,1,1,2,1,1,1,2,2];
if ( needle.length <= 0 ) return 0;
var fromStr = ','+haystack.toString()+','
var findStr = ','+needle.toString()+','
// Find ',1,2,1,1,2,1,' in ',1,2,1,1,2,1,1,1,2,2,'
var pos = fromStr.indexOf(findStr);
// Count the end position requested
return pos >= 0 ? fromStr.slice(0,pos+1).match(/,/g).length + needle.length - 1 : -1;
Note: The comma at head and tail is to make sure [22,12] doesn't match [2,1].