need to implement my algorithm using javascript - javascript

I have made small algorithm and want to implement it using javascript. Here is my algorithm
I have a data in data.json file in this format
[
"109 200",
"109 201",
"102 202",
"103 202"
]
What I am trying to do is
Create four array containers i.e. c1, c2, c3 and c4.
Put above data in c1 container as it is
loop through c1 and put the data in c4 in following format
"109",
"200",
"109",
"201",
"102",
"202",
"103",
"202"
loop through c1 and put them in c2 in this format
"109,200"
then check if c3 is empty then read first value from c2 and push it in c3.
repeat step 4 but this time put second data i.e. "109 201" from c1 in c2 in this format
"109,201"
then check if c3 is not empty then loop through c2 and check if any of these two values are repeated in c4. If it is repeated then repeat step 6 and 7 until it finds least amount of numbers from data.json.
This algorithm is not efficient but still I want to use this.
Here is my code.
var teams = [],
c1 = [], arr = [], left = [], right = [], j = 0,
show = function () {
var span = $('#list');
$.getJSON('data/data.json', function (ids) {
//c1.push(c);
for (var i = 0; i < ids.length; i++) {
var a = smallcontainer(ids);
var b = bigcontainer(ids);
var c;
if (c1 == "") {
c = a[0].split(" ");
console.log(c);
} else {
}
//console.log(c);
var id = ids[i];
teams = id;
$('<li>' + id + '</li>').appendTo(span);
}
});
},
smallcontainer = function (teams) { //arr
arr = [teams[j]];
j++;
return arr;
},
bigcontainer = function (ids) { //c3. in code it is left+right=result
for (var i = 0; i < ids.length; i++) {
var splitted = ids[i].split(" ");
left.push(splitted[0]);
right.push(splitted[1]);
}
var result = left.concat(right);
};
Update
data inside data.json file has four teams with two members in each team in this form
"109 200" = Team 1
"109 201" = Team 2
"102 202" = Team 3
"103 202" = Team 4
So now I have to compute the smallest number of people and it has to select one member from each team from this list and show their IDs. So the output for above would be
109
202
Latest update
I am still waiting for help
Solution
Here is the solution with the help of AlexBEll and PAEz. I used solution below which was basically solved by AlexBell
var data = [
"1009 2000",
"1009 2001",
"1002 2002",
"1003 2002",
"1004 2003",
"1005 2004",
"1006 2005",
"1007 2006",
"1007 2007",
"1008 2008",
"1009 2008",
"1010 2009",
"1011 2010",
"1012 2010"
];
var first = [], second = [], result = {}, out = '';
//Separe the ids
for(var i = 0; i < data.length; i++){
var el = data[i].split(' ');
first[i] = el[0];
second[i] = el[1];
}
for(var k = 0; k < first.length; k++){
//Count the elements
var nOfFirst = countElemnts(first, first[k]);
var nOfSecond = countElemnts(second, second[k]);
//If the first is in more that second take it
if(nOfFirst > nOfSecond){
result[first[k]] = 0;
//Else take the second
}else if(nOfFirst < nOfSecond){
result[second[k]] = 0;
//If is only one take it
}else{
result[first[k]] = 0;
}
}
function countElemnts(arr, el){
var count = 0;
for(var j = 0; j < arr.length; j++){
if(arr[j] == el)
count++;
}
//console.log(el+' : '+count);
return count;
}
for(var n in result){
out += 'The id n: '+n+' is in the list\n';
}
alert(out);

Does this work?....
var teams=[
"109 200",
"109 201",
"102 202",
"103 202"
];
var members ={};
var matesId='109';
// Members that won
var wins={};
// First lets find out how many teams a member is in
for (var i=0,length=teams.length; i<length;i++){
var temp = teams[i].split(' ');
for (var z=0,zlength=temp.length;z<zlength;z++){
if (!members[temp[z]]) members[temp[z]]={wins:0,totalTeams:0,id:temp[z]};
members[temp[z]].totalTeams=members[temp[z]].totalTeams+1;
}
teams[i]=[members[temp[0]],members[temp[1]]];
}
for (var i=0,length=teams.length; i<length;i++){
var member1=teams[i][0];
var member2=teams[i][1];
if (member1.totalTeams>member2.totalTeams){
member1.wins=member1.wins+1;
} else if (member1.totalTeams<member2.totalTeams){
member2.wins=member2.wins+1;
} else {
member1.wins=member1.wins+1;
member2.wins=member2.wins+1;
}
}
for (var i=0,length=teams.length; i<length;i++){
var member1=teams[i][0];
var member2=teams[i][1];
if (member1.wins>member2.wins){
if (wins[member2.id]!==true) wins[member1.id]=true;
} else if (member1.wins<member2.wins){
if (wins[member1.id]!==true) wins[member2.id]=true;
} else if (!wins[member1.id] && !wins[member2.id]) {
if (member1.id==matesId && member2.id==matesId) {
wins[matesId]=true;
} else{
// A draw, so pick one
Math.round(Math.random())==1 ? wins[member2.id]=true : wins[member1.id]=true;
}
}
}
var keys=Object.keys(wins);
var results=[];
results.push(keys.length);
for (var i=0,length=keys.length; i<length;i++){
results.push(keys[i]);
}
results=results.join('\n');
document.querySelector('#output').innerText=results;​
http://jsfiddle.net/PAEz/dLUqj/3/
EDIT: Updated it so its a little easier to read.
EDIT: Realised you dont need a draw and win, just a win will do.
LAST EDIT: Noticed one small error, it should all be right now.

Related

For each entry in a sub array add values

let b = [];
this.state.sidejobs.forEach((user) => {
console.log(user);
if (!b.hasOwnProperty(user.jobworker)) b[user.jobworker] = 0;
b[user.jobworker] += user.duration;
});
One entry in jobworker has an array with two ids... how do i split it and add the duration respectively.
Name ID Total Hours
Mike Smith 281 5
284,281 5
John Doe 284 21
Chris Smith 283 23
let b = [];
this.state.sidejobs.forEach((user) => {
var jobworkers = user.jobworker.toString().split(",");
for (var i = 0; i < jobworkers.length; i++) {
var worker = jobworkers[i].trim();
if (!b.hasOwnProperty(worker)) b[worker] = 0;
b[worker] += user.duration;
}
});
First of all, is b an array or an object? Or are you using it as both? I suspect you meant for it to be an anonymous object.
let b = {};
Secondly, it would really help to know the exact structure of user.jobworker (eg: call "JSON.stringify(user.jobworker)"). For now, I will assume that the structure of the user object is as follows:
{
name: "Mike Smith",
id: 281,
duration: 5,
jobworker: [284, 281]
}
If that is the case, all you have to do is
let b = {};
this.state.sidejobs.forEach((user) => {
for (var i = 0; i < user.jobworker.length; i++) {
if (!b.hasOwnProperty(user.jobworker[i])) b[user.jobworker[i]] = 0;
b[user.jobworker[i]] += user.duration;
}
});
If instead user.jobworker contains a comma-delimited string of ids (eg: user.jobworker = "284,281") then you will have to split the string first:
this.state.sidejobs.forEach((user) => {
var jobworkers = user.jobworker.split(",");
for (var i = 0; i < jobworkers.length; i++) {
var worker = jobworkers[i].trim();
if (!b.hasOwnProperty(worker)) b[worker] = 0;
b[worker] += user.duration;
}
});

How to simplify this D3 code?

I've got some CSV data that looks like this, showing pass rates by organisation by year:
org,org_cat,2004_passed,2004_total,2005_passed,2005_total,2006_passed,2006_total
GSK,industry,35,100,45,100,55,100
I'm working in D3, and I'd like to end up with a dictionary of organisations like this:
data = {
'GSK': {
'org_cat': 'industry',
'data': [
{ 'year': 2004, 'passed': 35, 'total': 100 },
{ 'year': 2005, 'passed': 45, 'total': 100 },
{ 'year': 2006, 'passed': 55, 'total': 100 }
]
]
}
Most of this is straightforward, but I've got very messy code for the year columns:
var data = {};
allData.forEach(function(d) {
data[d.org] = {
'category': d.org_cat,
'data': []
};
for (var k in d) {
var temp = {};
for (var k in d) {
if (patt.test(k)) {
var res = k.split("_");
if (res[0] in temp) {
temp[res[0]][res[1]] = +d[k];
} else {
temp[res[0]] = {};
temp[res[0]][res[1]] = +d[k];
}
}
}
var tempArr = [];
for (var y in temp) {
var tempDict = {};
tempDict.year = y;
tempDict.passed = temp[y].passed;
tempDict.total = temp[y].total;
tempArr.push(tempDict);
}
// TODO: sort by year in case the keys got shuffled
data[d.org].data = tempArr;
}
});
Is there a way to simplify this horrid code?
It's safe to assume that each row is a unique organisation.
I don't see why you need D3 to do this. You're code doesn't use it either. Here's how I would do it, I'm sure there's another simpler way but it may help you either way :
Jsfiddle : https://jsfiddle.net/thatOneGuy/dnvheznk/1/
I converted the data to JSON to use with JSFiddle, but you already know how to loop through CSV so just overwrite line 14 :
for (var i = 0; i < data.length; i++) { //loop through data array (this is so you can use this on a bigger sized array)
To your loop :
allData.forEach(function(d, i) { //but add the 'i' to index
Here is full commented code with converted JSON data :
var data = [{ //data set converted to JSON for easier use
"org": "GSK",
"org_cat": "industry",
"2004_passed": 35,
"2004_total": 100,
"2005_passed": 45,
"2005_total": 100,
"2006_passed": 55,
"2006_total": 100
}];
var newData = {}; //new data container
for (var i = 0; i < data.length; i++) { //loop through data array (this is so you can use this on a bigger sized array)
var thisObj = {}; //create empty object
thisObj.org_cat = data[i].org_cat; //set org_cat
thisObj.data = []; //set data to empty array to populate later
for (var key in data[i]) { //loop through data[i]
if (key != 'org' && key != 'org_cat') { //check this key is not org or org_cat
var thisData = {}; //create empty data object
var thisYear = key.toString().substring(0, 4); //get year by using substring
thisData.year = thisYear; //set year
thisData.passed = data[i][thisYear + '_passed']; //set passed at this year
thisData.total = data[i][thisYear + '_total']; //set total at this year
thisObj.data.push(thisData); //push this data to data array
}
}
var uniqueDates = []; //set empty array to use to remove duplicate items in data array
for (var j = 0; j < thisObj.data.length; j++) { //loop through data array created earlier
if (uniqueDates.indexOf(thisObj.data[j].year) < 0) { //if this year doesn't exist in unique array above, push it in
uniqueDates.push(thisObj.data[j].year); //push it in
} else {
thisObj.data.splice(j--, 1); //remove duplicate data
}
}
newData[data[i].org] = thisObj; //set data # current org to be object created above
}
console.log('newData', newData) //log new data

JavaScript module pattern gives unexpected results

I am just messing around with generating random human names in JS. I wanted to also practice using the module pattern but I can't get my function to return a normal array.
What I want to save is how often a letter (or set of letters) shows up after another letter.
So with 'jacob' and 'jarod' I should see that the letter 'a' came after the letter 'j' 2 times like this: myArray[j][a] //2
BUT what I have instead somehow turned the array into a set of properties and to figure out that 'a' comes up 2 times I have to check it this way : myArray.j.a //2
can someone explain why this is and how I can fix it?
var names = ['jacob', 'cameron', 'zach', 'lake', 'zander', 'casey', 'carl', 'jeff', 'jack', 'jarod', 'max', 'cat', 'mallory', 'dana', 'hannah', 'stu', 'abrham', 'isaac'];
var probabilities = (function(){
var nextLetterProbability = [];
function addProbability(index, letters){
if(nextLetterProbability[index] !== undefined){
if(nextLetterProbability[index][letters] !== undefined){
nextLetterProbability[index][letters] = nextLetterProbability[index][letters] + 1;
}
else
nextLetterProbability[index][letters] = 1;
}
else{
nextLetterProbability[index] = [];
nextLetterProbability[index][letters] = 1;
}
}
return {
learn:function(names, chainLength){
for (var i = 0; i < names.length; i++) {
var name = names[i];
for (var j = 0; j < name.length - chainLength; j++) {
var start = name[j];
var next = name.slice(j + 1, j + chainLength + 1)
addProbability(start, next);
};
};
},
getLearnedArray:function(){
return nextLetterProbability;
}
}
})();
var nextLetterProbability = []; needed to be var nextLetterProbability = {}; because it is an associative array and is handled as an object.

How do you sort multiple objects that contain arrays representing scores?

Given an array of objects like this:
competitors = [{
name: "Alice",
scores: [3,7,8,2,5]
}, {
name: "Bob",
scores: [4,4,5,6,8]
}, {
name: "Carol",
scores: [5,3,2,7,6]
}];
Given that lower scores are better, how can I sort them (rank them 1-3) such that the winner is the one who wins the most comparisons within each index?
For example, with Alice, Bob, and Carol, Alice should win because she has 3 wins (3<4<5, 2<6<7, 5<6<8) out of a possible 5.
A more complicated example is
competitors = [{
name: "Dave",
scores: [8,1,1,8,4]
}, {
name: "Eve",
scores: [1,5,4,5,2]
}, {
name: "Frank",
scores: [6,2,3,4,7]
}];
Here, Frank loses (1 win: 4<5<8), while Dave (2 wins: 1<2<5, 1<3<4) and Eve (2 wins: 1<6<8, 2<4<7) tie. So repeating the process with just Dave and Eve, you can break the tie. Eve wins the tie-breaker with 3 wins, 2 losses. The final ranking is Eve, Dave, Frank.
I will always know ahead of time the number of scores each competitor has (let's call it numJudges), as well as the range of possible scores (let's call it 1-numCompetitors). I'm also not concerned about browser support, other than webkit's javascript engine, so that means support for ECMAScript 5 and some 6 (es5-compat-table) like the array functions every, map, filter, and reduce.
I find it often helps breaking a a big task like this down into stages. I doubt if it's efficient, but it might be useful to you.
To begin: get an array containing the results for each competitor:
function getScores() {
return competitors.map(function (el) {
return el.scores;
});
}
var scores = getScores();
Then pull out the individual game information:
function getGames(scores) {
var games = [];
for (var i = 0, l = scores[0].length; i < l; i++) {
games.push(scores.map(function (el) {
return el[i];
}));
}
return games;
}
var games = getGames(scores);
Find the winners of each game:
function findWinners(games) {
return games.map(function (el) {
return el.indexOf(Math.min.apply(null, el));
});
}
var winners = findWinners(games);
And finally, update each competitor with their results.
function applyWinners(winners) {
winners.forEach(function (el, i) {
var competitor = competitors[el];
if (!competitor.results) competitor.results = [];
competitor.results.push(i);
});
}
applyWinners(winners);
console.log(competitors) // Alice wins [0, 3, 4], Carol wins [1, 2]
Fiddle
Note: I prefer #Tibos answer but this one is simpler.
You can use a sorting function (Array.sort):
function getWins(competitors, competitor) {
var scores = competitor.scores;
var wins = 0;
for (var i = 0, n = scores.length; i < n; i++) {
var win = true;
for (var j = 0, m = competitors.length; j < m; j++) {
// Do not compare the competitor with himself
if (competitors[j] !== competitor) {
// Do not count a win if someone beat him
if (competitors[j].scores[i] > scores[i]) {
win = false;
break;
}
}
}
if (win) {
wins++;
}
}
return wins;
}
// Sort competitors according to their wins
competitors.sort(function(a, b) {
return getWins(competitors, b) - getWins(competitors, a);
});
A special compare function that computes the wins on the next level for a tie can do this:
function compareArray(a, b) {
for (var i=0; i<a.length && i<b.length; i++)
if (a[i] != b[i])
return a[i] - b[i];
return a.length-b.length;
}
function addWins(c) {
var w = new Array(c.length);
for (var i=0; i<numJudges; i++) {
// if two players have scored equally, the first will win
var l = 0;
for (var j=1; j<c.length; j++)
if (c[j].scores[i] < c[l].scores[i])
l = j;
w[l] = (w[l]||0)+1;
}
for (var i=0; i<c.length; i++)
c[i].wins.push(w[i]||0);
}
for (var i=0; i<competitors.length; i++)
competitors[i].wins = [];
competitors.sort(function(a, b) {
var samelevel = competitors;
do {
var o = - compareArray(a.wins, b.wins)
if (o != 0)
return o;
var len = samelevel.length;
samelevel = samelevel.filter(function(c) {
return compareArray(c.wins, a.wins) == 0;
})
addWins(samelevel);
} while (samelevel.length < len);
return - compareArray(a.wins, b.wins);
});

Count distinct elements in array

I have data that comes from my server to datatables.
I'm successfully populating my table but in footer callback I want to do some statistics.
Lets say I have data like so:
var data = [{
date: '2013-05-12',
holiday: "One type of holiday",
dayType: "Weekend"
}, {
date: '2013-05-13',
holiday: "Another type",
dayType: "Weekend"
}, {
date: '2013-05-14',
holiday: "Another type",
dayType: "Work"
}, {
date: '2013-05-15',
holiday: "",
dayType: "Work"
}];
I would like to count number of days with different holidays.
Here is result I would like to get:
var summary= [
{
"One type of holiday": {
"work": 0,
"weekend": 1
}
},
{
"Another type": {
"work": 1,
"weekend": 1
}
}];
I've created a very simple code to simply aggregate holidays:
for (var i = 0; i < data.length; i++) {
//console.log(data[i].holiday);
/*other stuff here*/
if (data[i].holiday.length > 0)
summary[data[i].holiday] = summary[data[i].holiday] + 1 || 1;
}
but this gives me invalid results, because in my data array holiday contains spaces.
I need a way to fix this and to split holidays based on dayType.
MY SOLUTION:
My version of answer:
var summary = {}, d, tmp, type;
for (var i = 0; i < data.length; i++) {
var d = data[i];
if (d.holiday.length > 0) {
type = d.dayType == 'Weekend' || d.dayType == 'Free' ? 'Weekend' : 'Work';
tmp = summary[d.holiday];
if (!tmp) {
tmp = {
Weekend: 0,
Work: 0
};
summary[d.holiday] = tmp;
}
summary[d.holiday][type] += 1;
}
}
Because this is modified version of #Arun answer I'm not posting this as standalone answer.
I find my version easier to understand, hope someone find's it useful.
Try
var summary = [], summaryMap = {}, d, map, m;
for (var i = 0; i < data.length; i++) {
var d = data[i];
map = summaryMap[d.holiday];
if(!map){
map = {
Work: 0,
Weekend: 0
};
m = {};
m[d.holiday] = map;
summary.push(m);
summaryMap[d.holiday] = map;
}
map[d.dayType] += 1;
}
console.log(summary);
console.log(JSON.stringify(summary));
Demo: Fiddle
go for
console.log(Object.keys(summary).length);
instead of
console.log(summary.length);
Because you can get the number of elements in a js object by using the length attribute.
note: using Object.keys may lead you to browser compatibility issues. As its supported form IE 9 and Firefox 4. See more info in this MDN article.
you can find more info and solutions for this problem in this answer.
see the updated fiddle.
Here's my attempt:
var summary = [];
var holidayTypes = [];
var dayTypes = [];
//first work out the different types of holidays
for (var i = 0; i < data.length; i++) {
if(holidayTypes.indexOf(data[i].holiday) == -1){
//this is a new type of holiday
holidayTypes.push(data[i].holiday);
}
if(dayTypes.indexOf(data[i].dayType) == -1){
//new type of day.
dayTypes.push(data[i].dayType);
}
}
console.log('types of holiday: ' + JSON.stringify(holidayTypes));
console.log('types of day: ' + JSON.stringify(dayTypes));
for(index in holidayTypes){
var typeobj = {};
//create an object for each type of holiday
typeobj[holidayTypes[index]] = {};
for(index2 in dayTypes){
//initialize a count for each type of day
typeobj[holidayTypes[index]][dayTypes[index2]] = 0;
//iterate through the data and count the occurrences where the day AND holiday match.
//if they do, iterate the value.
for (var j = 0; j < data.length; j++){
if((data[j].holiday == holidayTypes[index])
&& (data[j].dayType == dayTypes[index2])){
typeobj[holidayTypes[index]][dayTypes[index2]]++;
}
}
}
summary.push(typeobj);
}
console.log(JSON.stringify(summary));
Fiddle here
Output:
[{"One type of holiday":{"Weekend":1,"Work":0}},{"Another type":{"Weekend":1,"Work":1}},{"":{"Weekend":0,"Work":1}}]
It works but is unlikely to be as efficient as the guys above!

Categories

Resources