Javascript array and information retrieve - javascript

Ok so I'm not even sure how to title this post but I have a little logical problem that I need help with. So on a front page of a website I need 4 boxes. These four boxes contain 1 image, 1 title, one date. The trick is, these four boxes need to be randomly generated from a list of 10. So in javascript is it possible to create something like an xml structure to pick 4 random from then populate... so the way I want it to work is...
Item 1
date
title
src
Item 2
date
title
src
Item 3
date
title
src
Is it possible to put the items in an array then access the properties of them after they are randomly selected? I could do this with PHP/MySQL but that's very unnecessary for this. any ideas? Thanks!

Short answer, yes. Long answer below.
var obj1 = {
date: "04/12/1989",
title: "My birthday",
src: "path_to_some_image.png"
}
var obj2 = {
date: "12/25/2011",
title: "Christmas",
src: "santa_claus.gif"
}
objs = [obj1, obj2];
rand = Math.floor(Math.random() * objs.length);
console.log(objs[rand].title + " is " + objs[rand].date);
// "My birthday is 04/12/1989"
// or "Christmas is 12/25/2011"

Sure, you can use Math.random for this purpose. Put your list in an Array, then pick a random number between 0 and 9 and choose that item. You'd do this four times and you're good to go... unless you don't want the same item twice (or more often) - which I am pretty sure is what you want. No repetition, I mean. That makes things more interesting, if you don't want a biased probability distribution. In that case, the algorithm goes like this:
i = Random number between 0 and 9 -> pick array[i]
if (i == 9) -> all is well, skip 3
if (i<9) -> swap array[i] and array[9]
j = Random number between 0 and 8 -> pick array[j]
if (j == 8) -> all well, skip 6
if (j < 8) -> swap array[j] and array[8]
k = Random number between 0 and 7 -> pick array[k]
...
You get the pattern.The method is also known as the Fisher-Yates Shuffle.

You should use an array of objects..
var items = [{
'date': 'date of item 1',
'title': 'title of item 1',
'src': 'url/of/image-1'},
{
'date': 'date of item 2',
'title': 'title of item 2',
'src': 'url/of/image-2'},
/* .. more items.. */
{
'date': 'date of item 9',
'title': 'title of item 9',
'src': 'url/of/image-9'},
{
'date': 'date of item 10',
'title': 'title of item 10',
'src': 'url/of/image-10'}];
for (var i = 1; i < 5; i++) {
var item = items.splice(Math.floor(Math.random() * (items.length)), 1)[0];
var el = document.getElementById('item-' + i);
// insert the info you want in the DOM .. i just add it as text..
el.innerHTML= item.date + ' - ' + item.title + ' - ' + item.src;
}
And use a pre-defined html
<div id="item-1"></div>
<div id="item-2"></div>
<div id="item-3"></div>
<div id="item-4"></div>
Demo at http://jsfiddle.net/qkMNb/1/

Related

Compare 'order' to 'products' array and print product names if in the order?

I have an array of products:
const products = {
{
id: item1,
name: 'My product',
price: 100
},
{
id: item2,
name: 'My other product',
price: 200
},
{
id: item3,
name: 'My other other product',
price: 150
}
}
I also have an order state which says which and how many products are in the order. In this instance there is 1 item1 and 2 item2 in the order:
const orderState = {
item1: 1,
item2: 2
}
How can I render the prodcut name and number of times its in the order? Im using React but I think vanilla JS is all thats needed for the solution.
My HTML output needs to be something like:
<ul>
<li>My product x1 = $1</li>
<li>My other product x2 = $4</li>
</ul>
The way you're storing your data is what seems to be giving you difficulty. First, make the array of products an actual array:
const products = [
{
id: item1,
name: 'My product',
price: 100
}, //...
];
Additionally, what is that item1 value? Is that an actual ID of some kind, like an integer? That's what you'll use to identify the products later.
Then for your "order state", create an object which holds an array of references to the products. Something like this:
const orderState = {
products: [
{
productID: item1,
quantity: 1
},
{
productID: item2,
quantity: 2
}
]
}
Now that you have a more sensible data structure, you can more easily operate on that structure. There are a variety of ways to build your output, and how you do it may depend heavily on what other tools you're using (such as template engines and such). But just to demonstrate the logic, let's build a simple string:
var output = '<ul>';
for (var i = 0; i < orderState.products.length; i++) {
var product = {};
for (var j = 0; j < products.length; j++) {
if (products[j].id == orderState.products[i].id) {
product = products[j];
break;
}
}
output += '<li>' + product.name + ' x' + orderState.products[i].quantity + ' = $' + (product.price * orderState.products[i].quantity) + '</li>';
}
output += '</ul>';
From this you can refactor and improve as needed. For example, the logic to find the product based on its id can be extracted into its own function, or perhaps even reduced to a one-liner using built-in JavaScript functionality or framework functionality. (underscore.js is good for functionality like that.)
But the basic idea is to keep the data structures sensibly organized. Then the code which operates on those structures becomes trivial.
With below solution you can get the names of selected products as per your question statement.
let productsOrderedIds = Object.keys(orderState);
let proNames = [];
for(let pro of products) {
if(productsOrderedIds.indexOf(pro.id) !== -1){
proNames.push(pro.name);
}
}
console.log(proNames);

Extract int value in index array?

So I have a question about this score table I made in html.
var puntenTelling= new Array(3,4,2,1,5);
var teamNamen = new Array(puntenTelling[0]+"Team1", puntenTelling[1]+"Team2",puntenTelling[2]+ "Team3", puntenTelling[3]+"Team4", puntenTelling[4]+"Team5");
puntenTelling.sort(function(a, b){return b-a});
teamNamen.sort();
teamNamen.reverse();
for (var i=0; i<5; i++) {
document.write("<tr><td>" + teamNamen[i]);
document.write("<td>" + puntenTelling[i] + "</td></tr>");
}
Basically this gives me a sorted table, which is sorted on points, and sorted on the teamnames linked to the points.
I have to include the points (puntenTelling) in the array of the teamNames since otherwise I can't sort it in the same way I can sort the points.
Now I am printing it out like this:
Teamname Points
5Team5 5
4Team2 4
3Team1 3
2Team3 2
1Team4 1
I would just like to get rid of the "5,4,3,2,1"
before the "Team5,Team2" etc.
How can I do this?
Your approach of concatenating points and team names is not very clean and robust (how about a team named 1860 Munich?) Much better would be to make an array of objects that contain both team name and its points, and work with this array:
var teamsWithPoints = [
{ name: "team1", points: 3 },
{ name: "team2", points: 4 },
{ name: "team3", points: 2 },
{ name: "team4", points: 1 }
];
teamsWithPoints.sort(function(a, b) { return b.points - a.points });
document.write("<table>");
teamsWithPoints.forEach(function(team) {
document.write("<tr>");
document.write("<td>" + team.name);
document.write("<td>" + team.points);
});
Seems to me that you need a dictionary (associative array) where the keys represent the team's order in the list. Sort the array by the keys, then just print the values. It could even be multidimensional where the key is the desired ranking position and the value contains the team name and the points.
When you're making the array, you're creating objects like this.
var teamNamen = new Array(puntenTelling[0]+"Team1", puntenTelling[1]+"Team2",puntenTelling[2]+ "Team3", puntenTelling[3]+"Team4", puntenTelling[4]+"Team5");
If you don't want the value to be included in the string value, you'd declare teamNamen like so.
var teamNamen = new Array("Team1", "Team2","Team3","Team4","Team5");
However, this will make your original sort not function properly. So you could try this following code to maintain the proper sorting functionality, while printing the correct value.
for (var i=0; i<5; i++) {
document.write("<tr><td>" + teamNamen[i].substring(1));
document.write("<td>" + puntenTelling[i] + "</td></tr>");
}

Sorting a threaded conversation

Not sure how to frame this one, but here goes.
It's a sorting algorithm question
Tools I have to play with are PostgresSQL and python (2.6) on the server and javascript/jquery at the browser end
I need to move data that describes a threaded conversation from a postgres DB to a web page. The data starts off in chronological order, I want to display in threads
Record numbers are small - should never be more than 100 messages returned
So, as a simple example, imagine the table:
ID Reply_To Text
=== ======== =============================
1 0 Hello World
2 0 Make me a sandwich
3 1 Hello back
4 2 No chance
5 1 Who are you?
6 5 Me of course
The end point I want to reach is
Hello World
Hello Back
Who are you?
Me of course
Make me a sandwich
No chance
Or, to put it another way...
ID Reply_To Text
=== ======== =============================
1 0 Hello World
3 1 Hello back
5 1 Who are you?
6 5 Me of course
2 0 Make me a sandwich
4 2 No chance
I'm not after a full solution here, all the ajax, json and formatting stuff I'm happy to get on with.
I'm just having issues getting my head around the neatest way to manage the sort.
SQL? Python? Javascript?
I'm currently playing with array sorts in Javascript (for no better reason than the fact that my python skills are exceptionally weak)
EDIT
At the moment I'm at something like:
function byThread(a,b) {
if (a.reply > b.id && a.reply != 0){
console.log("Compared id=" + a.id + " with id=" + b.id + " and returned -1 ")
return -1;
}
if (a.id > b.reply && b.reply != 0 ){
console.log("Compared id=" + a.id + " with id=" + b.id + " and returned 1 ")
return 1;
}
console.log("Compared id=" + a.id + " with id=" + b.id + " and returned 0 ")
return 0;
}
msg.sort(byThread);
And it's frustratingly close
I've tried to do this in pure sql, because I think that's where the logic should belong. What you need to do is find the list of ids from parent to child, and order by that. Luckily, postgres has array types which can be ordered, so we can use a recursive CTE:
with recursive threaded(id, reply_to, message, order_path) as (
select
parent.id,
parent.reply_to,
parent.message,
NULL::int[] || parent.id -- create an 1-element array with the parent id
from conversation parent
where parent.reply_to is null
UNION ALL
select
reply.id,
reply.reply_to,
reply.message,
t.order_path || reply.id -- append the reply id to the current path
from threaded t
join conversation reply on t.id = reply.reply_to
where reply.reply_to is not null
)
select * from threaded order by order_path;
And the results:
1 NULL "Hello World" "{1}"
3 1 "Hello Back" "{1,3}"
5 1 "Who are you?" "{1,5}"
6 5 "Me of course" "{1,5,6}"
2 NULL "Make me a sandwich" "{2}"
4 2 "No Chance" "{2,4}"
I'm not sure how this will perform though, so you should definitely test and profile this on your real dataset to make sure it's fine. If it's not, perhaps you could look at restructuring your data, and investigating different ways of storing "tree" data in a database. There is a library for django called django-mptt that can efficiently store and retrieve trees. The concept applies to databases in general, but the algorithms for pulling out trees and making sure they stay intact require changes to your application logic, better handled by a library.
Edit:
I should mention that I was originally using just the top-level id for "order_path" as a single number. This answer led me to using an array of ids to guarantee the order all the way down.
You could try something like this on JS side. Since this have replies inside replies, it'd be easy to build a DOM from the convoSorted
var convo = [{id: 1, replyTo: 0, text: "hello world"},
{id: 2, replyTo: 0, text: "Make me a sandwich"},
{id: 3, replyTo: 1, text: "hello back"},
{id: 4, replyTo: 2, text: "no chance"},
{id: 5, replyTo: 1, text: "who are you?"},
{id: 6, replyTo: 5, text: "me of course"},
{id: 7, replyTo: 0, text: "new question"},
{id: 8, replyTo: 7, text: "new answer"}];
var convoSorted = [];
function addToReplies(obj, rply){ //recursive function to find the q. to reply to.
if (obj.id == rply.replyTo){
obj.replies.push({id: rply.id, text: rply.text, replies: []}); //add to the replies array
}
else{
for (k = 0; k < obj.replies.length; k++){
addToReplies(obj.replies[k], rply);
}
}
}
function sortConvo(){
for (i = 0; i < convo.length; i++){
if (convo[i].replyTo == 0){ //if it's not a reply, add to sorted array
convoSorted.push({ id : convo[i].id, text: convo[i].text, replies: [] });
}
else{ //it's a reply, find the question it's replying
for (j = 0; j < convoSorted.length; j++){
addToReplies(convoSorted[j], convo[i]);
}
}
}
}
sortConvo();
console.log(convoSorted);
I feel an idiot - I've been over-complicating this.
All it needed was a bit of lateral thinking (which this discussion has helped with)
msgs=[
{id:1,reply:0,msg:'Hello World'},
{id:2,reply:0,msg:'Make me a sandwich'},
{id:3,reply:1,msg:'Hello back'},
{id:4,reply:2,msg:'No chance'},
{id:5,reply:1,msg:'Who are you?'},
{id:6,reply:5,msg:'Me of course'}
];
msgs.sort(function(a,b){
return a.reply - b.reply;
});
var conversation=$("<div id='threaded'>");
var list = $("<ul>")
.attr("id","thread_" + msgs[0].reply);
var message = $("<li>")
.text(msgs[0].msg)
.attr("id","msg_" + msgs[0].id);
$(list).append(message);
$(conversation).append(list);
for (i=1; i<msgs.length; i++){
var message = $("<li>")
.text(msgs[i].msg)
.attr("id","msg_" + msgs[i].id);
if ($(conversation).find("#msg_" + msgs[i].reply).length == 0){
$(conversation).find("ul:eq(0)").append(message);
} else {
var list = $("<ul>")
.attr("id","thread_" + msgs[i].id);
$(list).append(message);
$(conversation).find("#msg_" + msgs[i].reply).append(list);
}
}
Sometimes I forget just what a powerful tool the dom is

Accessing an element in an array within an array in JavaScript

Pastebin of index.html: http://pastebin.com/g8WpX6Wn (this works but with some broken img links & no css).
Zip file if you want to see whole project:
I'm trying to dynamically change the contents of a div when I click an image. The image has it's respective id (the first index in the inner array) within the first inner array there's another array (index 3). I want to populate my div (id="articleLinks") with those links using JQuery when the image is clicked.
JavaScript & JQuery:
The tube array. *Note: the first index of each element in tubeArray is the ID & the news articles aren't linked to anything particular. Only interested in tubeArray[0] & tubeArray[4]
var tubeArray = [
['UQ', -27.495134, 153.013502, "http://www.youtube.com/embed/uZ2SWWDt8Wg",
[
["example.com", "Brisbane students protest university fee hikes"],
["example.com", "Angry protests over UQ student union election"],
]
],
['New York', 40.715520, -74.002036, "http://www.youtube.com/embed/JG0wmXyi-Mw",
[
["example.com" , "NY taxpayers’ risky Wall Street bet: Why the comptroller race matters"]
]
],
['To The Skies', 47.09399, 15.40548, "http://www.youtube.com/embed/tfEjTgUmeWw",
[
["example.com","Battle for Kobane intensifies as Islamic State uses car bombs, Syrian fighters execute captives"],
["example.com","Jihadists take heavy losses in battle for Syria's Kobane"]
]
],
['Fallujah', 33.101509, 44.047308, "http://www.youtube.com/embed/V2EOMzZsTrE",
[
["example.com","Video captures family cat saving California boy from dog attack"],
["example.com","Fines of £20,000 for dogs that chase the postman"]
]
]
];
A for loop which goes through each element in tubeArray then assigns id to the first index. Also an image that calls the function myFunctionId which takes the parameter this.id.
for (i = 0; i < tubeArray.length; i++) {
var id = tubeArray[i][0];
//other code
'<img src="img.png" onclick="myFunctionId(this.id);" id="' + id + '">' +
//other code
}
function myFunctionId (id) {
journal = id;
alert(journal) //just a test
//I want to search through tubeArray with the id and find the matching inner array.
//I then want to loop through the innerArray and append to my html a link using JQuery.
for (j = 0; i < innerArray.length; j++){
//supposed to get "www.linkX.com"
var $link = ;
//supposed to get "titleX"
var $title = ;
//change the content of <div id="articleLinks">
$('#articleLinks').append('<a href=$link>$title</a><br>');
}
}
HTML:
<div id="articleLinks">
Example Link<br>
</div>
Any help would be greatly appreciated. I've tried to simplify & cut out as much as I can so it's readable.
probably this might help: make yourself a map like
var tubeArray = [
[ // tubeArray[0]
'id', // tubeArray[0][0]
int, // tubeArray[0][1]
int, // tubeArray[0][2]
[ // tubeArray[0][3]
[ // tubeArray[0][3][0]
"www.link1.com", // tubeArray[0][3][0][0]
"title1" // tubeArray[0][3][0][1]
],
[ // tubeArray[0][3][1]
"www.link2.com", // tubeArray[0][3][1][0]
"title2" // tubeArray[0][3][1][1]
]
]
],
etc.
don't know whether this helps, but four dimensional arrays are brain-breaking ....
[edit]
... and thus go for a more OO like approach:
var tubeArray = [
'id' : { // tubeArray[id] or tubeArray.id
'a': int, // tubeArray.id.a
'b': int, // tubeArray.id.b
'entries': [ // tubeArray.id.entries
{ // tubeArray.id.entries[0]
'url': "www.link1.com", // tubeArray.id.entries[0].url
'title': "title1"
},
{ // tubeArray.id.entries[1]
'url': "www.link2.com", // tubeArray.id.entries[1].url
'title': "title2" ...
}
]
] ,
First you need to loop over tubeArray then go 4 deep and loop over the Array of Arrays at that level. Of course, you loop over those inner Arrays and get Elements 0 and 1.
$.each(tubeArray, function(z, o){
$.each(o[4], function(i, a){
$.each(a, function(n, v){
$('#articleLinks').append("<a href='"+v[0]+"'>"+v[1]+'</a>'); // use CSS to break lines
});
});
}

Javascript Complex Possibilities

Straight to the point, I created a form letting user to insert 2 items (Option Name, Option Value)
The inserting number is dynamic such as:
**Option Name** **Option Value**
Color Red
Blue
Yellow
Size L
M
and I need to populate a table of the possibilities given by user like below:
**Color** **Size**
Red L
Red M
Blue L
Blue M ....etc
how can I write a javascript logic to do that? the worst problem is what if the user input 3 or 4 option name like adding material:cotton, chiffon sex: male, female?
It seems to be impossible or lots and lots of loop? I had been doing this for 2 weeks plus. Can anyone guide me through an easier way? I am almost stunned by this.
If you use a recursive function, you only need one loop and one if-else statement, no matter how many options there are:
var options = [{
name: "Color",
values: ["Red", "Blue"]
}, {
name: "Size",
values: ["M", "L"]
}, {
name: "Sex",
values: ["Male", "Female"]
}];
function list(options, result) {
if (options.length > 0) {
var option = options[0];
var remaining = options.slice(1);
for (var i = 0; i < option.values.length; i++) {
var current = result.slice(0);
current.push(option.values[i]);
list(remaining, current);
}
} else {
document.body.innerHTML += result.join(", ");
document.body.innerHTML += "<br/>";
}
}
list(options, []);
Fiddle available here.

Categories

Resources