I'm making a outfit randomizer. But I would like to add some rules to it to prevent weird outfits like a white tie on a white shirt. Or any tie on a graphic tee. Or wearing a turtleneck over a shirt.
This is the code, so far:
var shirts = ["White", "navy", "light blue", "gray"];
var pants = ["black", "navy", "gray"];
var ties = ["red and blue squares", "purple", "white", "red"];
var random_shirt = shirts[Math.floor(Math.random()*shirts.length)];
var random_pants = pants[Math.floor(Math.random()*pants.length)];
var random_tie = ties[Math.floor(Math.random()*ties.length)];
document.write( " shirt: " + random_shirt + " pants: " + random_pants + " tie: " + random_tie);
I know it's done with if's and else's, but I don't know how.
Please forgive my JS illiteracy. I learned it but never actually used it. Until now.
Thanks
There are severals ways of doing this, this is my suggestion:
You can filter the pants array based on the result of random shirt
var random_shirt = [random logic];
/*
This will iterate over your pants array, returning a filtered array
with containing the items that returned true
item: the actual item
index: index of the actual item
array: original array
*/
filtered_pants = pants.filter(function(item, index, array) {
if (item == random_shirt) {
// This item won't be in the filtered array
return false;
}
if ([another custom rule]) {
return false;
}
/*
After passing all the rules return true to include this item in
the filtered array
*/
return true;
});
// Now shuffle over the filtered array
var random_pants = filtered_pants[Math.floor(Math.random()*pants.length)];
Then just repeat it with the tie
Make sure to learn the documentation for the filter method ->
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
Alternatively you can use the reduce method which is similar -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
If you don't quite understand these methods, watch this playlist, it'll help a lot -> https://www.youtube.com/watch?v=BMUiFMZr7vk&list=PL0zVEGEvSaeEd9hlmCXrk5yUyqUag-n84
Related
I have arrays like this,
0: {"pure_id":"1","branch_id":"45"}
1: {"pure_id":"2","branch_id":"45"}
2: {"pure_id":"3","branch_id":"45"}
3: {"pure_id":"3","branch_id":"45"}
I am looking to group the above arrays into a single array based on pure_id, so the result array will be this below, and the index will be pure_id index
1: [{"pure_id":"1","branch_id":"45"}]
2: [{"pure_id":"2","branch_id":"45"}]
3: [{"pure_id":"3","branch_id":"45"},{"pure_id":"3","branch_id":"45"}]
I am trying lots of things honestly, but I cannot make it work.
Please help.
const result = [];
for(const el of array)
(result[el.pure_id] || (result[el.pure_id] = [])).push(el);
Using the new object literal rest and spread syntax, the property expression syntax, and .reduce() makes this pretty short and simple.
var arr = [
{"pure_id":"1","branch_id":"45"},
{"pure_id":"2","branch_id":"45"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"45"}
];
var result = arr.reduce((res, {pure_id, ...props}) =>
({...res, [pure_id]: (res[pure_id] || []).concat({pure_id, ...props})})
, {});
console.log(result);
The .reduce() is of course just creating a new object. Each iteration takes the accumulated properties and adds them to an object literal, but with the pure_id being the concatenation of the properties of the current object (copy) to an array.
I often see people struggle with something in programming that outside of it would not be a problem. Instead of arrays and objects, you can think of it as fruit.
Imagine a bucket of fruit. You want to sort the one bucket of fruit into 1 bucket for each color of fruit (color just being a property of a piece of fruit). So you would:
grab one fruit at a time
figure out it's color
if there is no bucket for that color, get one
put the fruit in the proper bucket
repeat until there are no fruits left
What we created was an algorithm for sorting fruit by color. The problem you are solving is very similar. In pseudocode it would be:
for each fruit
color = fruit.color
if not bucket[color]
make bucket[color]
put fruit in bucket[color]
to translate that to JS
var fruits = [
{color: "red"},
{color: "orange"},
{color: "pink"},
{color: "red"}
];
var buckets = {};
for (var i=0; i<fruits.length; i++) {
var fruit = fruits[i];
var color = fruit.color;
if (!buckets[color])
buckets[color] = [];
buckets[color].push(fruit);
}
So now, if you want to work with your array, the algorithm stays the same you just swap out the parts.
var things = [
{"pure_id":"1","branch_id":"45"},
{"pure_id":"2","branch_id":"45"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"45"}
];
var grouped = [];
for (let i=0; i<things.length; i++) {
var thing = things[i];
var id = thing['pure_id'];
if (!grouped[id])
grouped[id] = [];
grouped[id].push(thing);
}
console.log(grouped)
So, here we are at the first solution. It works! There are better solutions (using reduce, forEach or others) but don't let data structures like arrays or dictionaries scare you away. Think about it in simpler terms if it helps.
If don't use reduce, the codes will be like below:
Assuming your expected result is one array like:
[[{'pure_id':0, 'branch_id':1}], [{'pure_id':1, 'branch_id':2}]]
//assuming your array is like below:
var test = [{"pure_id":"1","branch_id":"43"},
{"pure_id":"2","branch_id":"44"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"46"}]
var result = []
var index_db = {} //use dict to save the mapping between the index of result and pure_id
var index = 0
test.forEach(function(item){
if(item.pure_id in index_db){
result[index_db[item.pure_id]].push(item)
}
else{
result.push([item])
index_db[item.pure_id] = index++
}
});
console.log(result)
Below is one reduce version:
//assuming your array is like below:
var test = [{"pure_id":"1","branch_id":"43"},
{"pure_id":"2","branch_id":"44"},
{"pure_id":"3","branch_id":"45"},
{"pure_id":"3","branch_id":"46"}]
result = test.reduce(function(pre, cur){
if(cur['pure_id'] in pre['indexes']){
pre['result'][pre['indexes'][cur['pure_id']]].push(cur)
}
else{
pre['result'].push([cur])
pre['indexes'][cur['pure_id']] = pre['pos']++
}
return pre
}, {'pos':0, 'indexes':{}, 'result':[]})
console.log(result['result'])
I'm grabbing a list of elements ids thusly.
var menus = $(".menu").map(function(){
return this.id;
});
Which returns something like:
["lunch", "appetizers", "soup", "salads", "seafood", "noodles", "stir_fry", "curry", "kids", "steak", "dessert", "sides"]
For each item in the array I want to grab some JSON data.
$.each(menus,function(i) {
var list = menus[i],
meal = data.menu.list,
items = '<li><h3>' + meal.name + '</h3><p>' + meal.desc + '</p></li>';
$('#'+list+".menu").append(items);
});
Such that data.menu.list would be data.menu.lunch, data.menu.appetizers, etc.
The JSON is structured like so:
{
"menu": {
"lunch": [{
"name": "Kao PAdd",
"desc": "Fried rice with onions, green onions, snow peas, and egg / Chicken, vegetarian / Shrimp or tofu (Add $1)"
}
Any thoughts that don't involve eval()?
EDIT:
I when I do this:
$.each(data.menu,function(i) {
console.log(data.menu[i].key);
});
the console gives me:
Object {lunch: Array(14), appetizer: Array(11)}
All I really want is to access those arrays.
console.log(data.menu[i].name)
gives me a pair of undefineds.
That’s a brilliant question, Sir!
No matter how you retrieve your menus, strToVar() will do the task.
This code converts strings from array to variable names:
Solution:
var strToVar = (str,val) => this[str] = val;
Example:
var menus = ["lunch", "appetizers", "soup", "salads", "seafood", "noodles",
"stir_fry", "curry", "kids", "steak", "dessert", "sides"];
menus.forEach(strToVar);
prompt("[lunch, appetizers, soup, salads, seafood, noodles, " +
"stir_fry, curry, kids, steak, dessert, sides]",
[lunch, appetizers, soup, salads, seafood, noodles,
stir_fry, curry, kids, steak, dessert, sides]);
Give me all your points.
If you're looking for parsing JSON string to object here you go:
var jsonString = '{"data":{"item":{"id":1,"value":"foo"}}}';
var jsonObj = JSON.parse(jsonString);
console.log(jsonObj.data.item.value);
The problem was, I didn't understand what I really wanted to do. I asked the wrong question (although it's an interesting one, so I'll leave it up).
I thought I needed to generate my variable list from the HTML ids, but that was a mistake. What I needed was simply another for loop (or jQuery each());
$.each(data.menu, function(i) {
var list = data.menu[i],
menus = [];
$.each(list, function(x) {
var items = '<li><h3>' + list[x].name + '</h3><p>' + list[x].desc + '</p></li>';
menus.push(items)
});
$('#' + i).append(menus);
});
Your $.each function should be:
$.each(menus, function(i, list) { // the second parameter is list so we don't need menus[i]
var meal = data.menu[list], // use of bracket notation
items = '<li><h3>' + meal.name + '</h3><p>' + meal.desc + '</p></li>';
$('#' + list).append(items);
// ^^^ no need for the ".menu" as IDs alone are sufficient (assuming you have unique IDs, otherwise you have a problem)
});
Docs on MDN for bracket notation.
As per my understanding you want to achieve something like this :
var menus = ["lunch", "appetizers", "soup", "salads"];
var menuList = [
{
"name":"lunch",
"description":"description1"
},
{
"name":"appetizers",
"description":"description2"
},
{
"name":"soup",
"description":"description3"
},
{
"name":"salads",
"description":"description4"
}
]
var menu = {};
for(var i in menus) {
menu[menus[i]] = [{
"name": menuList[i].name,
"desc": menuList[i].description
}];
}
console.log(menu);
trying to make this as simple to understand as possible...
I have a JS function that essentially picks which array (a list) a person has selected and then passes it to another function to then print that array out. The problem is I can't figure out how to use the array name that I have passed take a look:
Arrays:
var allLists =['list1', 'list2'];
var list1 = ['orange', 'pear', 'apple'];
var list2 = ['car', 'plane', 'bike'];
Function to loop through the lists:
function printAllLists() {
lists.forEach(function(entry) {
count++;
document.write("<h2> List Number " + count + "</h2>");
printList(entry);
});
}
Function to output each list contents to a table
function printList(listname) {
document.write("<table>");
document.write("List Name Is: " + listname);
listname.forEach(function(entry) { //HERE IS THE PROBLEM
document.write("<tr><td>");
document.write(entry);
document.write("</td></tr>");
});
document.write("</table>");
}
The problem I have is the line below literally uses "listname" rather than what has been passed as list name which should be either "list1" or "list 2"
listname.forEach(function(entry) {
So it just fails with this error. How can I get it to swap the name of the array instead. Sorry if its not really clear what I'm trying to say I'm not sure how to exactly word this (which is probably why google isn't helping.)
Uncaught TypeError: listname.forEach is not a function
JSFiddle
Link to JSFiddle - https://jsfiddle.net/38x5nw62/
Thanks
Do it like this:
var list1 = ['car', 'plane', 'bike'];
var list2 = ['car', 'plane', 'bike'];
var allLists = [list1, list2];
Working Code here: https://jsfiddle.net/38x5nw62/1/
You where using var allLists = ['list1', 'list2']; wich does only contain strings 'list1' and 'list2', NOT the variables/arrays named smiliarly to the strings.
I am making string contains values. I have company name, product and its value. I want to store these value in string but if user choose same product of same company then I want to only append product no only.
current string value TATA#434#tyre,TATA#234#door,TATA#687#tyre, and it should be as
TATA#434,687#tyre,TATA#234#door
as we can see user choose same company with same production, only product no. is different so we need to append only product no.
if customer choose all four product then string should be read like this
TATA#434,687#tyre,TATA#234#door,Maruti#8776#door
company and product can be increase. also in last entry how to remove ",".
Here is attached fiddle.
Code
var str="";
$('a').click(function(){
var el= $(this).parent();
str += el.find('#brand').text() + "#" + el.find('#no').text() + "#" + el.find('#product').text() +",";
console.log(str)
})
My real advice would be to use an object. Why? Because it makes your data manipulation SO much easier my friend.
Use something like:
function car(val1,val2,val3,val4) {
this.val1 = val1;
this.val2 = val2;
this.val3 = val3;
this.val4 = val4;
}
Now we can just make one with:
var item1 = new car("TATA#434","687#tyre","TATA#234#door","Maruti#8776#door");
Now you can change whatever you want.
If you would like further guidance on how to display this in the format you've suggested, more than happy to help.
Your solution involves many RegEx... which can turn sour quickly. As a large scale developer, I advice against this if there is any chance your values will change format in the future.
Using Arrays:
Here is a use case:
http://jsfiddle.net/k6XFy/1/
var a = ["TATA#434","687#tyre","TATA#234#door","Maruti#8776#door"];
function display(x){
alert(x);
}
alert(a[1]);
a[1] = "Convert";
alert(a[1]);
alert(a);
Edit:
You can join the array like so:
var a = ["TATA#434","687#tyre","TATA#234#door","Maruti#8776#door"];
function display(x){
alert(x);
}
var b = a.join(',');
alert(b);
View here: http://jsfiddle.net/k6XFy/3/
Why would you not store it in an object?
This is how I would store it.
{TATA: { 434: 'tyre', 234: 'door' }, Maruti: { 8776: 'door' }}
If you need to use it as a string, loop through it constructing the string when you need it.
EDIT:
I'm not sure the exact context, but perhaps this would even make sense:
{TATA: { tyre: [434,687], door: [234] }, Maruti: { door: [8776] }}
or
{ tyre: { TATA: [434,687] }, door: { Maruti: [8776], TATA: [234] }}
I need help on filtering an already filtered list.
Scenario is I have a list (li item with various classes) of products that is being filtered by an ID and that ID is being pushed into an array. E.g.
var $filtersSelected = [];
Using this code, I can successfully filter the list.
var $productItems = $('ul').find('li');
$.each($productItems, function() {
var $self = $(this),
// Store classes of each product <li> item
$classes = $self.attr('class').split(/\s+/),
$match = false;
// Check if any classes of each <li> matches those in '$filtersSelected' array
$.each($classes, function(i, c) {
if ($.inArray(c, $filtersSelected) > -1) {
$match = true;
}
return $classes;
});
// Do something
if ($match) {
$self.show();
} else {
$self.hide();
}
});
Every time I click a new filter ID, the array gets appended and any item whose classes matches those n the array gets shown. However, what I need is to be able to iterate through the already filtered items.
If I already have this items... $filtersSelected = ["blue"]
["blue", "circle", "number"]
["blue", "square", "number"]
["blue", "triangle", "letter"]
and click on "number". $filtersSelected = ["blue", "number"] I only need these items to show until it gets the exact match.
["blue", "circle", "number"]
["blue", "square", "number"]
Thanks in advance.
Here's a snippet of code and how it currently works. http://jsfiddle.net/athanph/ebLyV/24/
You'll see that I got 3 sets of filter. What I want is to filter exact items based on the filters chosen. If I click "Blue" all blue items will be shown, if I click "Circle" as my second filter, I only want to show blue and circle items, and so on...
I think what you are trying to do is this:
$('ul').find('li').filter(function(){
return this.className.indexOf($filtersSelected) > -1;
}).hide();
The other elements I suppose are already visible (i.e show()).
In above I am using some javascript code because I am not that much good with jquery. In short, I used what I know :).
If I understand well what you want, this is the code:
$(function () {
var filtersSelected = [];
$('#btAddToFilter').click(function () {
var x = '.' + $('#txtAddToFilter').val();
if ($.inArray(x, filtersSelected) < 0) {
filtersSelected.push(x);
}
$('#ulProductItems').find('li').hide();
$(filtersSelected.join(', ')).show()
});
});
http://jsfiddle.net/csicky/NKFTL/