Trouble at comparing arrays - javascript

I have 'shared.checkedFacility' scope array in controller which read something like:
[14, 49, 93, 122, 44, 40, 88, 83, 65, 9, 38, 28, 8, 53, 125, 155]
and i am dynamically generating two dimensional array in front end where, for example, single dimentional array from 'shared.facilities[$parent.$index]' read like
{"0":56,"1":13,"2":49,"3":3,"4":11,"5":7,"6":19,"7":4,"8":9,"9":131,"10":21}
Now i am comparing this two array in ng-show argument like
containsAny(shared.checkedFacility,shared.facilities[$index])
Where as function defination is like
function containsAny(source, target) {
console.log("contains called");
var result = source.filter(function(item) {
return target.indexOf(item) > -1
});
return (result.length > 0);
}
But some how this function is not returning true or false, how to make it work?
Please rescue me since i am afresh here in Angular or in Javascript Env straight from PHP.

You can use Object.keys(), .map() to create an array from shared.facilities[$parent.$index]
// `shared.checkedFacility`
var checkedFacility = [14
, 49
, 93
, 122
, 44
, 40
, 88
, 83
, 65
, 9
, 38
, 28
, 8
, 53
, 125
, 155
];
// shared.facilities[$parent.$index]
var facilities = {
"0": 56,
"1": 13,
"2": 49,
"3": 3,
"4": 11,
"5": 7,
"6": 19,
"7": 4,
"8": 9,
"9": 131,
"10": 21
};
// create an array having values contained in `facilities`
var arr = Object.keys(facilities).map(function(prop, index) {
return facilities[prop]
});
console.log(arr)
function containsAny(source, target) {
console.log("contains called");
var result = source.filter(function(item) {
return target.indexOf(item) > -1
});
return (result.length > 0);
}
// pass `arr` as second parameter to `containsAny`
var res = containsAny(checkedFacility, arr);
console.log(res)

Your function is failing on:
target.indexOf(item)
because target in your example is an Object and not an Array, so you can't call indexOf function.
So you are most likely getting:
Uncaught TypeError: target.indexOf is not a function
To solve that, you have to pass an Array as target instead of passing an Object.

Related

How can I get the largest number value along with the username from this array?

Im trying to get the user & value with the highest number from this array but have had no luck in my searches. I'm starting to wonder if my array is poorly written.
{
"radtech2": 1,
"conorlarkin4": 25,
"jdon2001": 15,
"nobel_veo": 101,
"frapoden": 1,
"duckyboy17": 31,
"faeded": 30,
"jimbob20001": 17,
"leb0wski": 15,
"3cavalry": 2,
"hardoak22": 25,
"deep_slide": 10000,
"sillywil": 7
}
const users = {
"radtech2": 1,
"conorlarkin4": 25,
"jdon2001": 15,
"nobel_veo": 101,
"frapoden": 1,
"duckyboy17": 31,
"faeded": 30,
"jimbob20001": 17,
"leb0wski": 15,
"3cavalry": 2,
"hardoak22": 25,
"deep_slide": 10000,
"sillywil": 7
};
const highestUser = users => Object.keys(users).reduce(
(highest, current) => highest.val > users[current] ? highest : { user: current, val: users[current] },
{ user: undefined, val: -Infinity }
).user;
console.log(highestUser(users));
Use keys() and entries() methods to search your JSON object. Save largest value into e.g. const largest and then find out which key belongs to this value.
Let me try to squeeze it into a one-liner approach using Object.keys() and Array.reduce().
const users = {
"radtech2": 1,
"conorlarkin4": 25,
"jdon2001": 15,
"nobel_veo": 101,
"frapoden": 1,
"duckyboy17": 31,
"faeded": 30,
"jimbob20001": 17,
"leb0wski": 15,
"3cavalry": 2,
"hardoak22": 25,
"deep_slide": 10000,
"sillywil": 7
};
const res = Object.keys(users).reduce((a, b) => users[a] > users[b] ? a : b);
console.log(res);
How the above code works is that I get the array of keys from the users object, and I use reduce to get the highest possible value and return the corresponding property from the array obtained from Object.keys().
What you show in your question is an Object, not an Array; however, it does need to be turned into an array in order to work with it.
You can do that with Object.entries(), which will return an array of all the key/value pairs in the object.
Then you can use Array.reduce() to extract the one with the largest value.
const data = {
"radtech2": 1,
"conorlarkin4": 25,
"jdon2001": 15,
"nobel_veo": 101,
"frapoden": 1,
"duckyboy17": 31,
"faeded": 30,
"jimbob20001": 17,
"leb0wski": 15,
"3cavalry": 2,
"hardoak22": 25,
"deep_slide": 10000,
"sillywil": 7
}
let winner = Object.entries(data).reduce((a, b) => (a[1] > b[1]) ? a : b)
console.log(winner)

Troubling removing string in Javascript array

I am having trouble understanding what to do next. The following code removes all the duplicate numbers but I also need to remove the strings without converting them to numbers. I'm not sure how to proceed...
var arr = [ 10, 44, 55 ,66 , 77 , 55 , 44 , 3 , 3 , 3 , 4 , 5 , 6 , 54 , "henry", "33", "£", "66"]
var max = {};
function biggerThanMax(arr){
return arr.filter(function(item,index){
return arr.indexOf(item) >= index;
});
};
biggerThanMax(arr)
use typeof x to check the type of variable x
You want to use typeof
var arr = [
10, 44, 55, 66, 77, 55, 44,
3, 3, 3, 4, 5, 6, 54,
"henry", "33", "£", "66"
]
var max = {};
function biggerThanMax(arr) {
return arr.filter(function(item, index) {
return typeof item == 'number' && arr.indexOf(item) >= index;
});
};
console.log(biggerThanMax(arr))
You also have a couple of typos (which are likely a typo in your example)
Unclosed array
Missing biggerThanMax opening bracket.

Extract data from an array of Object

I have this array of Object that I am getting from my database:
[Array of Object][1]
I would like to make an array of array for each value, but I can't manage to find a way to do it as I'm a beginner of javascript.
For example :
var Stats=[
[39,49,43,42,41,35], //SGW Value for each Object
[37,44,49,46,52,42], //UD Value for each Object
[8,11,8,8,16,15], //Virtual Value for each Object
...
]
The goal is to make a chart on chart.js that look like that :
[Chart Goal][2]
I would need to loop the dataset because I'll add more data and it would be way too long to set each dataset individually.
Thanks for your time.
You can do it like this:
let array1 = [
{
param1: 10,
param2: 20
},
{
param1: 30,
param2: 40
}
]
let array2 = array1.map(item => Object.values(item));
console.log(array2); // prints [[10, 20], [30, 40]]
First of all you need to create an array for each property you want to plot; i.e.:
var fsp = [],
msg = [],
sgw = [];
Then you can loop over your dataset and put the data in each array:
yourArray.forEach(function(obj){
//obj takes the value of each object in the database
fsp.push(obj.fsp);
msg.push(obj.msg);
sgw.push(obj.sgw);
})
or, if you are more familiar with for loop
for(var obj of yourArray){
fsp.push(obj.fsp);
msg.push(obj.msg);
sgw.push(obj.sgw);
}
Finally you can create an array as you pointed in your example
var result = [];
result.push(fsp, msg, sgw);
And the result will be
[
[89, 59, 43, 60, 81, 34, 28, 58, 75, 41],
[77, 91, 4, 56, 6, 1, 42, 82, 97, 18],
[24, 34, 4, 13, 75, 34, 14, 41, 20, 38]
]
For more informations take a look at Array.forEach(), Array.push() and for...of documentations
EDIT
As you pointed in your comment, you can generate arrays dynamically creating an object like var arrays = {};. Then in forEach(), or if for...of, you need to loop over objects with a for...in loop. The variable you declare in loop's head takes the value of index, numeric for Arrays, literal for Objects. You have to do something like:
yourArray.forEach(function(obj){
for(let index in obj){
if(!arrays[index]) // check if property has already been set and initialized
arrays[index] = []; // if not, it's initialized
arrays[index].push(obj[index]) // push the value into the array
}
})
Note that Object has been treated as Array because you access its properties with a variable filled at runtime.
The result will be:
arrays = {
fsp: [89, 59, 43, 60, 81, 34, 28, 58, 75, 41],
msg: [77, 91, 4, 56, 6, 1, 42, 82, 97, 18],
sgw: [24, 34, 4, 13, 75, 34, 14, 41, 20, 38]
}
To obtain only arrays use Object.values().
If you cannot imagine how this works, I suggest you to make some examples in Chrome Developer Tools' console, or in Node's console, or wherever you can have a realtime feedback, putting in the middle of code some console.log() of variables

Selectively flattening a nested JSON structure

So this is a problem that I have no idea where to even start so even just a pointer in the right direction would be great.
So I have data that looks like so:
data = {
"agg": {
"agg1": [
{
"keyWeWant": "*-20.0",
"asdf": 0,
"asdf": 20,
"asdf": 14,
"some_nested_agg": [
{
"keyWeWant2": 20,
"to": 25,
"doc_count": 4,
"some_nested_agg2": {
"count": 7,
"min": 2,
"max": 5,
"keyWeWant3": 2.857142857142857,
"sum": 20
}
},
{
"keyWeWant2": 25,
"to": 30,
"doc_count": 10,
"some_nested_agg2": {
"count": 16,
"min": 2,
"max": 10,
"keyWeWant3": 6.375,
"sum": 102
}
}
]
},
{
...
},
{
...
},
...
]
}
}
Now from the example, within 'agg' there are N 'agg1' results, within each 'agg1' result there is a 'keyWeWant'. Each 'agg1' result also has a list of 'some_nested_agg' results which each contain a 'keyWeWant2'. Each 'keyWeWant2' value is associated a single 'keyWeWant' value somewhere up in the hierarchy. Similarly each 'keyWeWant2' also contains a set of results for 'some_nested_agg2' (not a list but rather a map this time). Each of the set of results contains a 'keyWeWant3'.
Now I want to flatten this structure while still preserving the association between 'keyWeWant', 'keyWeWant2', and 'keyWeWant3' (I'm essentially de-normalizing) to get something like so:
What I want the function to look like:
[
{
"keyWeWant" : "*-20",
"keyWeWant2" : 20,
"keyWeWant3" : 2.857142857142857
},
{
"keyWeWant" : "*-20",
"keyWeWant2" : 25,
"keyWeWant3" : 6.375
},
{
...
},
{
...
}
]
This is an example where there is only depth 3 but there could be arbitrary depth with some nested values being lists and some being arrays/list.
What I would like to do is write a function to take in the keys I want and where to find them, and then go get the keys and denormalize.
Something that looks like:
function_name(data_map, {
"keyWeWant" : ['agg', 'agg1'],
"keyWeWant2" : ['agg', 'agg1', 'some_nested_agg'],
"keyWeWant" : ['agg', 'agg1', 'some_nested_agg', 'some_nested_agg2']
})
Any ideas? I'm familiar with Java, Clojure, Java-script, and Python and am just looking for a way to solve this that's relatively simple.
Here is a JavaScript (ES6) function you could use:
function flatten(data, keys) {
var key = keys[0];
if (key in data)
keys = keys.slice(1);
var res = keys.length && Object.keys(data)
.map( key => data[key] )
.filter( val => Object(val) === val )
.reduce( (res, val) => res.concat(flatten(val, keys)), []);
return !(key in data) ? res
: (res || [{}]).map ( obj => Object.assign(obj, { [key]: data[key] }) );
}
// Sample data
var data = {
"agg": {
"agg1": [
{
"keyWeWant": "*-20.0",
"asdf": 0,
"asdf": 20,
"asdf": 14,
"some_nested_agg": [
{
"keyWeWant2": 20,
"to": 25,
"doc_count": 4,
"some_nested_agg2": {
"count": 7,
"min": 2,
"max": 5,
"keyWeWant3": 2.857142857142857,
"sum": 20
}
},
{
"keyWeWant2": 25,
"to": 30,
"doc_count": 10,
"some_nested_agg2": {
"count": 16,
"min": 2,
"max": 10,
"keyWeWant3": 6.375,
"sum": 102
}
}
]
},
]
}
};
// Flatten it by array of keys
var res = flatten(data, ['keyWeWant', 'keyWeWant2', 'keyWeWant3']);
// Output result
console.log(res);
Alternative using paths
As noted in comments, the above code does not use path information; it just looks in all arrays. This could be an issue if the keys being looked for also occur in paths that should be ignored.
The following alternative will use path information, which should be passed as an array of sub-arrays, where each sub-array first lists the path keys, and as last element the value key to be retained:
function flatten(data, [path, ...paths]) {
return path && (
Array.isArray(data)
? data.reduce( (res, item) => res.concat(flatten(item, arguments[1])), [] )
: path[0] in data && (
path.length > 1
? flatten(data[path[0]], [path.slice(1), ...paths])
: (flatten(data, paths) || [{}]).map (
item => Object.assign(item, { [path[0]]: data[path[0]] })
)
)
);
}
// Sample data
var data = {
"agg": {
"agg1": [
{
"keyWeWant": "*-20.0",
"asdf": 0,
"asdf": 20,
"asdf": 14,
"some_nested_agg": [
{
"keyWeWant2": 20,
"to": 25,
"doc_count": 4,
"some_nested_agg2": {
"count": 7,
"min": 2,
"max": 5,
"keyWeWant3": 2.857142857142857,
"sum": 20
}
},
{
"keyWeWant2": 25,
"to": 30,
"doc_count": 10,
"some_nested_agg2": {
"count": 16,
"min": 2,
"max": 10,
"keyWeWant3": 6.375,
"sum": 102
}
}
]
},
]
}
};
// Flatten it by array of keys
var res = flatten(data, [
['agg', 'agg1', 'keyWeWant'],
['some_nested_agg', 'keyWeWant2'],
['some_nested_agg2', 'keyWeWant3']]);
// Output result
console.log(res);
There is probably a better way to solve this particular problem (using some ElasticSearch library or something), but here's a solution in Clojure using your requested input and output data formats.
I placed this test data in a file called data.json:
{
"agg": {
"agg1": [
{
"keyWeWant": "*-20.0",
"asdf": 0,
"asdf": 20,
"asdf": 14,
"some_nested_agg": [
{
"keyWeWant2": 20,
"to": 25,
"doc_count": 4,
"some_nested_agg2": {
"count": 7,
"min": 2,
"max": 5,
"keyWeWant3": 2.857142857142857,
"sum": 20
}
},
{
"keyWeWant2": 25,
"to": 30,
"doc_count": 10,
"some_nested_agg2": {
"count": 16,
"min": 2,
"max": 10,
"keyWeWant3": 6.375,
"sum": 102
}
}]
}]}
}
Then Cheshire JSON library parses the data to a Clojure data structure:
(use '[cheshire.core :as cheshire])
(def my-data (-> "data.json" slurp cheshire/parse-string))
Next the paths to get are defined as follows:
(def my-data-map
{"keyWeWant" ["agg", "agg1"],
"keyWeWant2" ["agg", "agg1", "some_nested_agg"],
"keyWeWant3" ["agg", "agg1", "some_nested_agg", "some_nested_agg2"]})
It is your data_map above without ":", single quotes changed to double quotes and the last "keyWeWant" changed to "keyWeWant3".
find-nested below has the semantics of Clojure's get-in, only then it works on maps with vectors, and returns all values instead of one.
When find-nested is given a search vector it finds all values in a nested map where some values can consist of a vector with a list of maps. Every map in the vector is checked.
(defn find-nested
"Finds all values in a coll consisting of maps and vectors.
All values are returned in a tree structure:
i.e, in your problem it returns (20 25) if you call it with
(find-nested ['agg', 'agg1', 'some_nested_agg', 'keyWeWant2']
my-data).
Returns nil if not found."
[ks c]
(let [k (first ks)]
(cond (nil? k) c
(map? c) (find-nested (rest ks) (get c k))
(vector? c) (if-let [e (-> c first (get k))]
(if (string? e) e ; do not map over chars in str
(map (partial find-nested (rest ks)) e))
(find-nested ks (into [] (rest c)))) ; create vec again
:else nil)))
find-nested finds the values for a search path:
(find-nested ["agg", "agg1", "some_nested_agg", "keyWeWant2"] my-data)
; => (20 25)
If all the paths towards the "keyWeWant's are mapped over my-data these are the slices of a tree:
(*-20.0
(20 25)
(2.857142857142857 6.375))
The structure you ask for (all end results with paths getting there) can be obtained from this tree in function-name like this:
(defn function-name
"Transforms data d by finding (nested keys) via data-map m in d and
flattening the structure."
[d m]
(let [tree (map #(find-nested (conj (second %) (first %)) d) m)
leaves (last tree)
leaf-indices (range (count leaves))
results (for [index leaf-indices]
(map (fn [slice]
(if (string? slice)
slice
(loop [node (nth slice index)]
(if node
node
(recur (nth slice (dec index)))))))
tree))
results-with-paths (mapv #(zipmap (keys m) %) results)
json (cheshire/encode results-with-paths)]
json))
results uses a loop to step back if a leaf-index is larger than that particular slice. I think it will work out for deeper nested structures as well -if a next slice is always double the size of a previous slice or the same size it should work out -, but I have not tested it.
Calling (function-name my-data my-data-map) leads to a JSON string in your requested format:
[{
"keyWeWant": "-20.0",
"keyWeWant2": 20,
"keyWeWant3": 2.857142857142857 }
{
"keyWeWant": "-20.0",
"keyWeWant2" 25,
"keyWeWant3" 6.375 }]
/edit
I see you were looking for a relatively simple solution, that this is not. :-) maybe there is one without having it available in a library. I would be glad to find out how it can be simplified.

Pairing multiple javascript arrays

I'm trying to solve a problem I have with multiple javascript arrays.
So basically the result I want is to match the arrays of a dropdown box with other values from other arrays that I will display.
The arrays contain different values, but the order is the most important thing
var array1 = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22];
var array2 = [30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50];
var array3 = [36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56];
Let's say the user selects number 4, then I need to somehow select 32 in array2 and 38 in array3.
Any suggestions are gladly accepted, Thanks!
Get the index from the first array, with Array.prototype.indexOf
var index = array1.indexOf(4);
Get the values from other arrays with that index, like this
console.log(array2[index], array3[index]);
Note: If the value being searched is not found in the array, indexOf will not fail with an error but it will simply return -1. So, you might want to check before using that to access the elements from other arrays, like this
var index = array1.indexOf(4);
if (index !== -1) {
console.log(array2[index], array3[index]);
} else {
console.log("Invalid element selected");
}
Any time you have multiple parallel arrays, you should really consider refactoring it into a single array of objects. That way you never have to worry about keeping them synched. For example:
var myArray = [ { val1: 2, val2: 30, val3: 36 }, { val1: 4, val2: 32, val3: 38 }, ...];
Now to find the value for 4 you can simply do something like (although a simple for loop might be more efficient since you know there is only ever one result):
var myValues = myArray.filter(function(item) { return item.val1 === 4 });
And then access myValues[0].val2 and myValues[0].val3.
Or, if you are always looking up by the first value, you can use that as your key for an object that maps to your other two values. Something like:
var myArray = { 2: { val2: 30, val3: 36 }, 4: { val2: 32, val3: 38 },...};
Now if you want the other two values for 4 you can simply:
var value2 = myArray[4];
var value3 = myArray[4];
Assuming those are not only arrays and values, but you have actual <select> dropdown boxes:
Accessing the selected value is not only possible by using select1.value, but also by using select1.options[select1.selectedIndex].value. That.selectedIndex is what we are interested in, and you can use that equivalently on the option collections of the other two dropdowns, or the arrays with their values:
select2.options[select1.selectedIndex].value
array2[select1.selectedIndex]
select3.options[select1.selectedIndex].value
array3[select1.selectedIndex]
If you access them via the options collection you will need to make sure that one option is actually selected (select1.selectedIndex != -1), otherwise you'd get an exception.
Do it like this,
var valueFromSelect = 4;
var array1 = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22];
var array2 = [30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50];
var array3 = [36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56];
for(var i = 0; i < array1.length; i++){
if(valueFromSelect == array1[i]){
console.log(array2[i], array3[i]);
break;
}
}
I suggest you don't use indexOf, it's not compatible with IE < 9 read more about that here indexOf MDN

Categories