jQuery dynamically generate grep() - javascript

I'm using $.grep() to pull back a set of JSON results like so:
myObject.appJSON = jQuery.grep(myObject.appJSON, function (a) {
return a.category == "Entertainment";
});
and it works fine. But what I really want to do eventually is have several checkboxes so that that I can filter on several different things. I realize to do that I can just do something like:
myObject.appJSON = jQuery.grep(myObject.appJSON, function (a) {
return (a.category == "Entertainment" && a.category == "Business");
});
But my real question here is how to have this happen dynamically, so I can essentially build up a string of features for the grep to return. Maybe I'm showing how novice I am here but it would almost be nice to be able to generate the long filter string then just pop it into the return. It looks like as it is now, the return has to be hard coded.
I realize this is probably simple but there's very little out there on the net about how to do this kind of thing.
Thanks in advance!

You can search an array like this:
myObject.appJSON = jQuery.grep(myObject.appJSON, function (a) {
return $.inArray(a.category, someArray) > -1;
});

I think you can regexp the match:
var filter = function(categories) {
var obj = [];
$.each(categories.split(' '), function(cat) {
obj.push(jQuery.grep(myObject.appJSON, function (a) {
return cat.test(a.category);
}));
});
return obj;
}
var filtered_array = filter('Entertainment Business');

You could use eval() to create your grep logic dynamically. Or you could create a regular expression matching all your categories. But the easiest thing to do is create an object which contains your categories and check if a.category is one of them.
var categories = {
"Entertainment": 1,
"Business": 1
};
myObject.appJSON = jQuery.grep(myObject.appJSON, function (a) {
return categories[a.category];
});

Related

search within an array in javascript

I've been trying for a while now to search within an array, I've looked at all the other questions that even somewhat resemble mine and nothing works, so I'm asking for any help you can give now..
I have an array with a more complex insides than a simple string array
var elementDefns = [
{"element":"water", "combos": {"air":"steam", "earth":"sand"} },
{"element":"fire", "combos": {"earth":"lava", "air":"energy"} },
{"element":"air", "combos": {"water":"steam", "earth":"dust"} },
{"element":"earth", "combos": {"water":"swamp", "fire":"lava"} },
];
Two elements are picked (by the users) which are combined to create new elements. I'd like to search through the elements for any combos that can be made. Ideally, I'd want to use Array.prototype.find, although I can't figure out how to use polyfills correctly and i'm unsure if i'm writing it correctly, so it continues to not work
var elementOne = $("#board img:first-child").attr('id');
var elementTwo = $("#board img:last-child").attr('id');
function findElement(element) {
return elementDefns.element === elementOne;
}
board is the id div where the element cards go to once clicked. I also tried a loop
for (var i=0, tot=elementDefns.length; i < tot; i++) {
var indexHelp = elementDefns[i].element;
var find = indexHelp.search(elementOne);
console.log(find);
}
I'm trying to post a question that's not too long, but I'm sure there's lots more about my code i need to adjust in order to do this. I guess I'm just asking if there's something obvious you think i could work on. I've looked at most of the answers on this site to similar problems but its all just going horribly wrong so any other support would be greatly appreciated..
I have an array with a more complex insides than a simple string array
Yes, but why? Get rid of the extra layers and this is trivial
var e1 = "water";
var e2 = "air";
var elementDefns = {
"water": {"combos": {"air":"steam", "earth":"sand"} },
"fire": {"combos": {"earth":"lava", "air":"energy"} },
"air": {"combos": {"water":"steam", "earth":"dust"} },
"earth": {"combos": {"water":"swamp", "fire":"lava"} },
};
elementDefns[e1].combos[e2] = > "steam"
If you want to keep your data-structure, you can filter through it like this:
var matches = elementDefns
.filter(e => e.element == first && e.combos[second] !== null)
.map(e => e.combos[second]);
The first row filters out all matches, and the secon maps it over to the actual match-string (element name). The find() you speak of just returns the first value that matches, and i guess you want all, so that would be the filter() method.

DC.js, crossfilter - running reduce() on groupAll()

This feels like it should be easy :/
The crossfilter API says I can run a reduce on groupAll:
https://github.com/square/crossfilter/wiki/API-Reference#groupAll_reduce
But I cannot get it to work. I've tried facts.groupAll() where var facts = crossfilter(data); And I've tried all.reduce() where var all = facts.groupAll(). I've tried with and without brackets and googled for examples. Does anyone know of a working example? I want a single output across all my rows.
I realise my reduce function isn't complete and looks complicated. It works fine reducing a dimension, but gives undefined for groupAll on facts.
Thanks
var accumGrp = facts.groupAll().reduce(
function(p,v) {
for (var i=0; i<supplierFields[0].length; i++) {
if (!p.population[supplierFields[0][i]]) { p.population[supplierFields[0][i]] = []; }
p.population[supplierFields[0][i]].push(v[supplierFields[0][i]+'_l']);
}
return p;
},
function(p,v) { return p; },
function() {
var obj = {};
obj.population = {};
obj.highlight = {};
return obj;
}
);
print_filter('accumGrp');
Your basic problem here is probably that you need to call groupAll.value() in order to execute the group aggregation, whereas regular groups calculate aggregations at the time of definition or data load, not when you query them with group.top or group.all.
It looks like your basic approach is otherwise correct, and I can't see what print_filter does, so it's just a guess, but try calling console.log(accumGrp.value()) at the end of your script and see if it works.
If not, here is a short working example to reference:
var data = [1,2,3,4]
var cf = crossfilter(data)
var grp = cf.groupAll().reduce(
function(p, d) { return p + d },
function(p, d) { return p - d },
function() { return 0 }
)
console.log(grp.value())
This prints 10. And here is a working JSFiddle where you can try things out (with a few more console statements that might help look into what is going on): https://jsfiddle.net/esjewett/39xgn5ah/1/

Javascript Search in Object Array Like SQL By Object Key

For example, i have an array like this:
var arr = [
{"keyword": "Sample 1", "item": {"title":"Sample Title", "url": "/sample"}},
{"keyword": "Foo 1", "item": {"title":"Foo Title", "url": "/sample"}}
];
I want to search in the "keyword" key, like when a user presses a key from their input and return that matches objects.
If user presses to "s" key, then first [0], element must return. Like using the SQL LIKE statement.
$("#query").on('keypress', function () {
var result = $.grep(keywords, function(e){
//I do not know what should i do here.
});
});
If you want to use $.grep you can do it like this:
$("#query").on('keyup', function() {
var search = this.value.toLowerCase();
var result = $.grep(keywords, function(el) {
return el.keyword.toLowerCase().indexOf(search) > -1;
});
});
Demo: http://jsfiddle.net/9TPSa/
Also note, that I switched to keyup event to be able to read updated this.value.
Use the Array.prototype.filter method:
Array.prototype.filterBy = function(attr, value) {
return this.filter(function(elem){
return elem[attr].indexOf(value) !== -1;
});
}
Then arr.filterBy('keyword', '1') would return both the objects(in your arr array), while arr.filterBy('keyword', 'oo') would return only the second one.
DEMO
The answer is simple: YOu have to loop through all of your objects, look at each keyword entry and decide wether it matches your search or not. SOmething like this:
var results = [];
for (var i = 0 ; i < arr.length ; i++) {
if (arr[i].keyword == "what ever you are looking for") {
results.push(arr[i]);
}
}
If you only need the frist match (and not all of them), you can simplify it:
var result;
for (var i = 0 ; i < arr.length ; i++) {
if (arr[i].keyword == "what ever you are looking for") {
result = arr[i];
break;
}
}
If you're not looking for equality, but need to use placeholders, take al look at String.prototype.indexOf() or regular expressions.
If you want to use $.grep() at all costs (there isn't too much difference to looping manually though, it does loop as well, just itnernally), you can - it'd look like this:
$("#query").on('keypress', function () {
var result = $.grep(keywords, function(e){
return (e.keyword == "whatever you are looking for again");
// use regular expressions or .indexOf again if you don't want to test equallity
});
});
Looping over large strucutres however (as you're comparing to databases, I suspect you have A LOT of those objects inside arr?) is very inefficient however. The fact that you HAVE TO loop indicates bad design. If you really got a lot of them, you might consider using a data structure that supports indexing, like a Hash Table/Map (those are not implemented in the core Java API; but are easy to implement on yoru own). They won't work if you need placeholders though, they're only an advantage when using equality to match results.
You could try using jQuery UI's AutoComplete... http://jqueryui.com/autocomplete/
You'll have to reduce your array to just the fields you're wanting to be searchable (ie. string literals for the keyword property, like ["Sample 1", "Foo 1"]) and pass that as the source in the autocomplete options.
Then hook into the change event http://api.jqueryui.com/autocomplete/#event-change and pull out the rest of your object from the original array.
EDIT : If you want to use grep, here is an example that gets the results using that method, but how you display them as auto options is then the next step!
http://jsfiddle.net/eQp3h/
var arr = [
{"keyword": "Sample 1", "item": {"title":"Sample Title", "url": "/sample"}},
{"keyword": "Foo 1", "item": {"title":"Foo Title", "url": "/sample"}}
];
$("#query").on('keyup', function () {
var regExp = new RegExp("^" + $(this).val(), "i");
var result = $.grep(arr, function(e, i){
var match = regExp.test(e.keyword);
return match;
});
$("#results").text(JSON.stringify(result));
});
Try this
$("body").on("keyup","#query",function(e){
var str = $("#query").val().toLowerCase();
var newarr = $.grep(arr,function(n,i){
return n.keyword.toLowerCase().search(str)!=-1;
});
});

Use Javascript or jQuery to create an array from an array

Assume you have an array:
var arrStateCityAll=['CA_Alameda','CA__Pasadena','CA_Sacramento','NY_Albany','NY_Buffalo','NY_Ithaca']
Is there an easy way using javascript and/or jQuery to filter the arrStateCityAll to get a new array (a subset of arrStateCityAll); something like this:
// return's ['CA_Alameda','CA__Pasadena','CA_Sacramento']
var arrStateCityCA=FilterArray('CA',arrStateCityAll);
Likely you want to do a regex on each item. You can do this with jQuery's grep function.
http://api.jquery.com/jQuery.grep/
You can use javascript's Array.filter.
var arrStateCityAll = ['CA_Alameda','CA__Pasadena','CA_Sacramento','NY_Albany','NY_Buffalo','NY_Ithaca']
var arrStateCityCA = arrStateCityAll.filter( function (element) {
return element.indexOf("CA_") == 0;
});
The mozilla documentation linked to above has a solution for browsers that don't implicitly support filter.
This should work.
var arrStateCityCA = [];
for (var i = 0;i<arrStateCityAll.length;i++){
if (arrStateCityAll[i].substr(0,2) == 'CA'){
arrStateCityCA.push(arrStateCityAll[i]);
}
}
You could use jQuery.grep
var arrStateCityCA =
$.grep(arrStateCityAll,function(el,i){return (el.substring(0,2)=='CA')});
Demo at jsfiddle
To implement you actual FilterArray function as shown in your post you could do
function FilterArray(state,arr){
return $.grep(arr,
function(el,i) {return (el.substring(0,2)==state)}
);
}
This makes a few assumptions.
State is always 2 chars.
State is always the first 2 chars.
And of course remember case-sensitivity (this function is case sensitive) ie 'CA' not equal to 'Ca'.
if you are going to have an undescore between your state and city name, you can split on the underscore and test against the first array value
function getSubSetByState(set,state) {
var result = [];
for(var i=0,l=set.length;i<l;++i) {
if(set[i].split('_')[0] === state) {
result.push(set[i]);
}
}
return result;
}
Use if by giving it the set of places, and then the state you are searching for.

Better way to see if an array contains an object?

I have an array of items (terms), which will be put as <option> tags in a <select>. If any of these items are in another array (termsAlreadyTaking), they should be removed first. Here is how I have done it:
// If the user has a term like "Fall 2010" already selected, we don't need that in the list of terms to add.
for (var i = 0; i < terms.length; i++)
{
for (var iAlreadyTaking = 0; iAlreadyTaking < termsAlreadyTaking.length; iAlreadyTaking++)
{
if (terms[i]['pk'] == termsAlreadyTaking[iAlreadyTaking]['pk'])
{
terms.splice(i, 1); // remove terms[i] without leaving a hole in the array
continue;
}
}
}
Is there a better way to do this? It feels a bit clumsy.
I'm using jQuery, if it makes a difference.
UPDATE Based on #Matthew Flaschen's answer:
// If the user has a term like "Fall 2010" already selected, we don't need that in the list of terms to add.
var options_for_selector = $.grep(all_possible_choices, function(elem)
{
var already_chosen = false;
$.each(response_chosen_items, function(index, chosen_elem)
{
if (chosen_elem['pk'] == elem['pk'])
{
already_chosen = true;
return;
}
});
return ! already_chosen;
});
The reason it gets a bit more verbose in the middle is that $.inArray() is returning false, because the duplicates I'm looking for don't strictly equal one another in the == sense. However, all their values are the same. Can I make this more concise?
var terms = $.grep(terms, function(el)
{
return $.inArray(el, termsAlreadyTaking) == -1;
});
This still has m * n performance (m and n are the lengths of the arrays), but it shouldn't be a big deal as long as they're relatively small. To get m + n, you could use a hashtable
Note that ECMAScript provides the similar Array.filter and Array.indexOf. However, they're not implemented in all browsers yet, so you would have to use the MDC implementations as a fallback. Since you're using jQuery, grep and inArray (which uses native indexOf when available) are easier.
EDIT:
You could do:
var response_chosen_pk = $.map(response_chosen_items, function(elem)
{
return elem.pk;
});
var options_for_selector = $.grep(all_possible_choices, function(elem)
{
return $.inArray(elem.pk, response_chosen_pk) == -1;
});
http://github.com/danstocker/jorder
Create a jOrder table on termsAlreadyTaking, and index it with pk.
var table = jOrder(termsAlreadyTaking)
.index('pk', ['pk']);
Then you can search a lot faster:
...
if ([] == table.where([{ pk: terms[i].pk }]))
{
...
}
...

Categories

Resources