Add st, nd, rd and th (ordinal) suffix to a number - javascript

I would like to dynamically generate a string of text based on a current day. So, for example, if it is day 1 then I would like my code to generate = "Its the <dynamic>1*<dynamic string>st</dynamic string>*</dynamic>".
There are 12 days in total so I have done the following:
I've set up a for loop which loops through the 12 days.
In my html I have given my element a unique id with which to target it, see below:
<h1 id="dynamicTitle" class="CustomFont leftHeading shadow">On The <span></span> <em>of rest of generic text</em></h1>
Then, inside my for loop I have the following code:
$("#dynamicTitle span").html(i);
var day = i;
if (day == 1) {
day = i + "st";
} else if (day == 2) {
day = i + "nd"
} else if (day == 3) {
day = i + "rd"
}
UPDATE
This is the entire for loop as requested:
$(document).ready(function () {
for (i = 1; i <= 12; i++) {
var classy = "";
if (daysTilDate(i + 19) > 0) {
classy = "future";
$("#Day" + i).addClass(classy);
$("#mainHeading").html("");
$("#title").html("");
$("#description").html("");
} else if (daysTilDate(i + 19) < 0) {
classy = "past";
$("#Day" + i).addClass(classy);
$("#title").html("");
$("#description").html("");
$("#mainHeading").html("");
$(".cta").css('display', 'none');
$("#Day" + i + " .prizeLink").attr("href", "" + i + ".html");
} else {
classy = "current";
$("#Day" + i).addClass(classy);
$("#title").html(headings[i - 1]);
$("#description").html(descriptions[i - 1]);
$(".cta").css('display', 'block');
$("#dynamicImage").attr("src", ".." + i + ".jpg");
$("#mainHeading").html("");
$(".claimPrize").attr("href", "" + i + ".html");
$("#dynamicTitle span").html(i);
var day = i;
if (day == 1) {
day = i + "st";
} else if (day == 2) {
day = i + "nd"
} else if (day == 3) {
day = i + "rd"
} else if (day) {
}
}
}

The rules are as follows:
st is used with numbers ending in 1 (e.g. 1st, pronounced first)
nd is used with numbers ending in 2 (e.g. 92nd, pronounced ninety-second)
rd is used with numbers ending in 3 (e.g. 33rd, pronounced thirty-third)
As an exception to the above rules, all the "teen" numbers ending with 11, 12 or 13 use -th (e.g. 11th, pronounced eleventh, 112th,
pronounced one hundred [and] twelfth)
th is used for all other numbers (e.g. 9th, pronounced ninth).
The following JavaScript code (rewritten in Jun '14) accomplishes this:
function ordinal_suffix_of(i) {
var j = i % 10,
k = i % 100;
if (j == 1 && k != 11) {
return i + "st";
}
if (j == 2 && k != 12) {
return i + "nd";
}
if (j == 3 && k != 13) {
return i + "rd";
}
return i + "th";
}
Sample output for numbers between 0-115:
0 0th
1 1st
2 2nd
3 3rd
4 4th
5 5th
6 6th
7 7th
8 8th
9 9th
10 10th
11 11th
12 12th
13 13th
14 14th
15 15th
16 16th
17 17th
18 18th
19 19th
20 20th
21 21st
22 22nd
23 23rd
24 24th
25 25th
26 26th
27 27th
28 28th
29 29th
30 30th
31 31st
32 32nd
33 33rd
34 34th
35 35th
36 36th
37 37th
38 38th
39 39th
40 40th
41 41st
42 42nd
43 43rd
44 44th
45 45th
46 46th
47 47th
48 48th
49 49th
50 50th
51 51st
52 52nd
53 53rd
54 54th
55 55th
56 56th
57 57th
58 58th
59 59th
60 60th
61 61st
62 62nd
63 63rd
64 64th
65 65th
66 66th
67 67th
68 68th
69 69th
70 70th
71 71st
72 72nd
73 73rd
74 74th
75 75th
76 76th
77 77th
78 78th
79 79th
80 80th
81 81st
82 82nd
83 83rd
84 84th
85 85th
86 86th
87 87th
88 88th
89 89th
90 90th
91 91st
92 92nd
93 93rd
94 94th
95 95th
96 96th
97 97th
98 98th
99 99th
100 100th
101 101st
102 102nd
103 103rd
104 104th
105 105th
106 106th
107 107th
108 108th
109 109th
110 110th
111 111th
112 112th
113 113th
114 114th
115 115th

From Shopify
function getNumberWithOrdinal(n) {
var s = ["th", "st", "nd", "rd"],
v = n % 100;
return n + (s[(v - 20) % 10] || s[v] || s[0]);
}
[-4,-1,0,1,2,3,4,10,11,12,13,14,20,21,22,100,101,111].forEach(
n => console.log(n + ' -> ' + getNumberWithOrdinal(n))
);

Minimal one-line approach for ordinal suffixes
function nth(n){return["st","nd","rd"][((n+90)%100-10)%10-1]||"th"}
(this is for positive integers, see below for other variations)
Explanation
Start with an array with the suffixes ["st", "nd", "rd"]. We want to map integers ending in 1, 2, 3 (but not ending in 11, 12, 13) to the indexes 0, 1, 2.
Other integers (including those ending in 11, 12, 13) can be mapped to anything else—indexes not found in the array will evaluate to undefined. This is falsy in javascript and with the use of logical or (|| "th") the expression will return "th" for these integers, which is exactly what we want.
The expression ((n + 90) % 100 - 10) % 10 - 1 does the mapping. Breaking it down:
(n + 90) % 100: This expression takes the input integer − 10 mod 100, mapping 10 to 0, ... 99 to 89, 0 to 90, ..., 9 to 99. Now the integers ending in 11, 12, 13 are at the lower end (mapped to 1, 2, 3).
- 10: Now 10 is mapped to −10, 19 to −1, 99 to 79, 0 to 80, ... 9 to 89. The integers ending in 11, 12, 13 are mapped to negative integers (−9, −8, −7).
% 10: Now all integers ending in 1, 2, or 3 are mapped to 1, 2, 3. All other integers are mapped to something else (11, 12, 13 are still mapped to −9, −8, −7).
- 1: Subtracting one gives the final mapping of 1, 2, 3 to 0, 1, 2.
Verifying that it works
function nth(n){return["st","nd","rd"][((n+90)%100-10)%10-1]||"th"}
//test integers from 1 to 124
for(var r = [], i = 1; i < 125; i++) r.push(i + nth(i));
//output result
document.getElementById('result').innerHTML = r.join('<br>');
<div id="result"></div>
Variations
Allowing negative integers:
function nth(n){return["st","nd","rd"][(((n<0?-n:n)+90)%100-10)%10-1]||"th"}
function nth(n){return["st","nd","rd"][(((n<0?-n:n)+90)%100-10)%10-1]||"th"}
//test integers from 15 to -124
for(var r = [], i = 15; i > -125; i--) r.push(i + nth(i));
//output result
document.getElementById('result').innerHTML = r.join('<br>');
<div id="result"></div>
In ES6 fat arrow syntax (anonymous function):
n=>["st","nd","rd"][(((n<0?-n:n)+90)%100-10)%10-1]||"th"

Intl.PluralRules, the standard method.
I would just like to drop the canonical way of doing this in here, as nobody seems to know it. Do not reinvent the wheel.
If you want your code to be
self-documenting
easy to localize
with the modern standard
― this is the way to go.
const english_ordinal_rules = new Intl.PluralRules("en", {type: "ordinal"});
const suffixes = {
one: "st",
two: "nd",
few: "rd",
other: "th"
};
function ordinal(number/*: number */) {
const category = english_ordinal_rules.select(number);
const suffix = suffixes[category];
return (number + suffix);
} // -> string
const test = Array(201)
.fill()
.map((_, index) => index - 100)
.map(ordinal)
.join(" ");
console.log(test);
The Intl.PluralRules constructor (Draft ECMA-402)
Unicode’s six plurality categories
Code-golf
While I do not recommend golfing with your code and killing the readability, I came up with one for those golfers (92 bytes):
n=>n+{e:"st",o:"nd",w:"rd",h:"th"}[new Intl.PluralRules("en",{type:"ordinal"}).select(n)[2]]

You can use the moment libraries local data functions.
Code:
moment.localeData().ordinal(1)
//1st

By splitting the number into an array and reversing we can easily check the last 2 digits of the number using array[0] and array[1].
If a number is in the teens array[1] = 1 it requires "th".
function getDaySuffix(num)
{
var array = ("" + num).split("").reverse(); // E.g. 123 = array("3","2","1")
if (array[1] != "1") { // Number is not in the teens
switch (array[0]) {
case "1": return "st";
case "2": return "nd";
case "3": return "rd";
}
}
return "th";
}

You've only got 12 days? I'd be tempted to make it just a simple lookup array:
var suffixes = ['','st','nd','rd','th','th','th','th','th','th','th','th','th'];
then
var i = 2;
var day = i + suffixes[i]; // result: '2nd'
or
var i = 8;
var day = i + suffixes[i]; // result: '8th'

function getSuffix(n) {return n < 11 || n > 13 ? ['st', 'nd', 'rd', 'th'][Math.min((n - 1) % 10, 3)] : 'th'}

I wrote this function to solve this problem:
// this is for adding the ordinal suffix, turning 1, 2 and 3 into 1st, 2nd and 3rd
Number.prototype.addSuffix=function(){
var n=this.toString().split('.')[0];
var lastDigits=n.substring(n.length-2);
//add exception just for 11, 12 and 13
if(lastDigits==='11' || lastDigits==='12' || lastDigits==='13'){
return this+'th';
}
switch(n.substring(n.length-1)){
case '1': return this+'st';
case '2': return this+'nd';
case '3': return this+'rd';
default : return this+'th';
}
};
With this you can just put .addSuffix() to any number and it will result in what you want. For example:
var number=1234;
console.log(number.addSuffix());
// console will show: 1234th

An alternative version of the ordinal function could be as follows:
function toCardinal(num) {
var ones = num % 10;
var tens = num % 100;
if (tens < 11 || tens > 13) {
switch (ones) {
case 1:
return num + "st";
case 2:
return num + "nd";
case 3:
return num + "rd";
}
}
return num + "th";
}
The variables are named more explicitly, uses camel case convention, and might be faster.

const getOrdinalNum = (n) => n + (n > 0 ? ['th', 'st', 'nd', 'rd'][(n > 3 && n < 21) || n % 10 > 3 ? 0 : n % 10] : '');

I wrote this simple function the other day. Although for a date you don't need the larger numbers, this will cater for higher values too (1013th, 36021st etc...)
var fGetSuffix = function(nPos){
var sSuffix = "";
switch (nPos % 10){
case 1:
sSuffix = (nPos % 100 === 11) ? "th" : "st";
break;
case 2:
sSuffix = (nPos % 100 === 12) ? "th" : "nd";
break;
case 3:
sSuffix = (nPos % 100 === 13) ? "th" : "rd";
break;
default:
sSuffix = "th";
break;
}
return sSuffix;
};

function ordsfx(a){return["th","st","nd","rd"][(a=~~(a<0?-a:a)%100)>10&&a<14||(a%=10)>3?0:a]}
See annotated version at https://gist.github.com/furf/986113#file-annotated-js
Short, sweet, and efficient, just like utility functions should be. Works with any signed/unsigned integer/float. (Even though I can't imagine a need to ordinalize floats)

Strongly recommend the excellent date-fns library. Fast, modular, immutable, works with standard dates.
import * as DateFns from 'date-fns';
const ordinalInt = DateFns.format(someInt, 'do');
See date-fns docs: https://date-fns.org/v2.0.0-alpha.9/docs/format

Here is another option.
function getOrdinalSuffix(day) {
if(/^[2-3]?1$/.test(day)){
return 'st';
} else if(/^[2-3]?2$/.test(day)){
return 'nd';
} else if(/^[2-3]?3$/.test(day)){
return 'rd';
} else {
return 'th';
}
}
console.log(getOrdinalSuffix('1'));
console.log(getOrdinalSuffix('13'));
console.log(getOrdinalSuffix('22'));
console.log(getOrdinalSuffix('33'));
Notice the exception for the teens? Teens are so akward!
Edit: Forgot about 11th and 12th

Old one I made for my stuff...
function convertToOrdinal(number){
if (number !=1){
var numberastext = number.ToString();
var endchar = numberastext.Substring(numberastext.Length - 1);
if (number>9){
var secondfromendchar = numberastext.Substring(numberastext.Length - 1);
secondfromendchar = numberastext.Remove(numberastext.Length - 1);
}
var suffix = "th";
var digit = int.Parse(endchar);
switch (digit){
case 3:
if(secondfromendchar != "1"){
suffix = "rd";
break;
}
case 2:
if(secondfromendchar != "1"){
suffix = "nd";
break;
}
case 1:
if(secondfromendchar != "1"){
suffix = "st";
break;
}
default:
suffix = "th";
break;
}
return number+suffix+" ";
} else {
return;
}
}

I wrote this function for higher numbers and all test cases
function numberToOrdinal(num) {
if (num === 0) {
return '0'
};
let i = num.toString(), j = i.slice(i.length - 2), k = i.slice(i.length - 1);
if (j >= 10 && j <= 20) {
return (i + 'th')
} else if (j > 20 && j < 100) {
if (k == 1) {
return (i + 'st')
} else if (k == 2) {
return (i + 'nd')
} else if (k == 3) {
return (i + 'rd')
} else {
return (i + 'th')
}
} else if (j == 1) {
return (i + 'st')
} else if (j == 2) {
return (i + 'nd')
} else if (j == 3) {
return (i + 'rd')
} else {
return (i + 'th')
}
}

Here's a slightly different approach (I don't think the other answers do this). I'm not sure whether I love it or hate it, but it works!
export function addDaySuffix(day: number) {
const suffixes =
' stndrdthththththththththththththththththstndrdthththththththst';
const startIndex = day * 2;
return `${day}${suffixes.substring(startIndex, startIndex + 2)}`;
}

I would like to quote the answer available in the link
function ordinal(n) {
var s = ["th", "st", "nd", "rd"];
var v = n%100;
return n + (s[(v-20)%10] || s[v] || s[0]);
}

I wanted to provide a functional answer to this question to complement the existing answer:
const ordinalSuffix = ['st', 'nd', 'rd']
const addSuffix = n => n + (ordinalSuffix[(n - 1) % 10] || 'th')
const numberToOrdinal = n => `${n}`.match(/1\d$/) ? n + 'th' : addSuffix(n)
we've created an array of the special values, the important thing to remember is arrays have a zero based index so ordinalSuffix[0] is equal to 'st'.
Our function numberToOrdinal checks if the number ends in a teen number in which case append the number with 'th' as all then numbers ordinals are 'th'. In the event that the number is not a teen we pass the number to addSuffix which adds the number to the ordinal which is determined by if the number minus 1 (because we're using a zero based index) mod 10 has a remainder of 2 or less it's taken from the array, otherwise it's 'th'.
sample output:
numberToOrdinal(1) // 1st
numberToOrdinal(2) // 2nd
numberToOrdinal(3) // 3rd
numberToOrdinal(4) // 4th
numberToOrdinal(5) // 5th
numberToOrdinal(6) // 6th
numberToOrdinal(7) // 7th
numberToOrdinal(8) // 8th
numberToOrdinal(9) // 9th
numberToOrdinal(10) // 10th
numberToOrdinal(11) // 11th
numberToOrdinal(12) // 12th
numberToOrdinal(13) // 13th
numberToOrdinal(14) // 14th
numberToOrdinal(101) // 101st

I strongly recommend this, it is super easy and straightforward to read. I hope it help?
It avoid the use of negative integer i.e number less than 1 and return false
It return 0 if input is 0
function numberToOrdinal(n) {
let result;
if(n < 0){
return false;
}else if(n === 0){
result = "0";
}else if(n > 0){
let nToString = n.toString();
let lastStringIndex = nToString.length-1;
let lastStringElement = nToString[lastStringIndex];
if( lastStringElement == "1" && n % 100 !== 11 ){
result = nToString + "st";
}else if( lastStringElement == "2" && n % 100 !== 12 ){
result = nToString + "nd";
}else if( lastStringElement == "3" && n % 100 !== 13 ){
result = nToString + "rd";
}else{
result = nToString + "th";
}
}
return result;
}
console.log(numberToOrdinal(-111));
console.log(numberToOrdinal(0));
console.log(numberToOrdinal(11));
console.log(numberToOrdinal(15));
console.log(numberToOrdinal(21));
console.log(numberToOrdinal(32));
console.log(numberToOrdinal(43));
console.log(numberToOrdinal(70));
console.log(numberToOrdinal(111));
console.log(numberToOrdinal(300));
console.log(numberToOrdinal(101));
OUTPUT
false
0
11th
15th
21st
32nd
43rd
70th
111th
300th
101st

This is for one liners and lovers of es6
let i= new Date().getDate
// I can be any number, for future sake we'll use 9
const j = I % 10;
const k = I % 100;
i = `${i}${j === 1 && k !== 11 ? 'st' : j === 2 && k !== 12 ? 'nd' : j === 3 && k !== 13 ? 'rd' : 'th'}`}
console.log(i) //9th
Another option for +be number would be:
console.log(["st","nd","rd"][((i+90)%100-10)%10-1]||"th"]
Also to get rid of the ordinal prefix just use these:
console.log(i.parseInt("8th"))
console.log(i.parseFloat("8th"))
feel free to modify to suit you need

<p>31<sup>st</sup> March 2015</p>
You can use
1<sup>st</sup>
2<sup>nd</sup>
3<sup>rd</sup>
4<sup>th</sup>
for positioning the suffix

Related

Function luckymoney in chinese culture

I have an assessment in JavaScript which is a little bit odd. Here it is:
Goal:
In Chinese culture, it is common during celebrations to give "red
envelopes" containing a little money. Most often, the adult
generations give to the younger generations. You want to build a
WeChat application to help grandparents share their donation budget
between their grandchildren.
Write a program that calculates the number of "lucky gifts" (equal to 8) according to the money budget and the number of giftees grandchildren
Functioning:
Many rules, mixing tradition and superstition, frame this gift:
Donations should not contain amount 4, as it sounds like "dead"
it is auspicious to donate an amount of 8, as it sounds like "fortune"
it would be frowned upon not to give anything to one of the
grandchildren
your algorithm must return the number of donations equal to 8 while
respecting the following rules:
Spend the entire budget (unless there is enough budget to give everyone 8)
Give no 4 (by tradition, the budget will never be 4)
Give no 0 (unless the budget is not sufficient)
Score a maximum of 8 once the above rules are respected
Implementation:
Implement the function luckyMoney(money,giftees) which :
take as inputs the integers money and giftees with:
0 <=money< 100
0 <=giftees<10
and returns the number of donations equal to 8 as an integer
Examples:
Case 1:
Inputs
12
2
Ouput
0
Case 2:
inputs
24
4
Ouput
2
Case 3
Inputs
7
2
Output
0
First of all, I don't quite understand the Case2 of the examples given above, as inputs we have money which is worth 24 and giftees which is equals to 4, after Euclidean division by 8, we get the number of gifts equals to 8 as an integer and 24 divided by 8, we get 3, but why the output is 2 instead of 3.
Did I miss something?
So I went ahead and implement the function as follows:
function luckyMoney(money,giftees){
if (money % 8 ===0){
return (money/8)
}else if(money%4===0){
return 0}
}
In fact I am going in circles and I do not know how to express the different conditions of the functioning part in my code,
Can you give me a hand please?
my attemp
function luckyMoney(money, giftees) {
if (money < 0 || money >= 100) return -1; //incorrect money input
if (giftees < 0 || giftees >= 10) return -2; //incorrect giftees input
if (money >= giftees * 8) return giftees; //spend the entire budget (unless there is enough budget to give everyone 8)
if (money < giftees) return 0; // not enough money
let b = money, g = giftees; // enough budget for giftees left after donating 8 as much as possible
while (b >= 8 + (g - 1) && g > 0) {
b -= 8;
g--;
}
if(g === 1 && b === 4) return 0;
return giftees - g;
}
console.log('inputs: 12 2, result: ', luckyMoney(12,2));
console.log('inputs: 24 4, result: ', luckyMoney(24,4));
console.log('inputs: 7 2, result: ', luckyMoney(7,2));
console.log('inputs: 64 9, result: ', luckyMoney(64,9));
console.log('inputs: 60 8, result: ', luckyMoney(60,8));
Here's a general algorithm you could follow. Hint: you can generalise the steps using a loop.
1. Try to give everyone eight. Does you have enough budget?
Yes: You have found the solution: all giftees get 8
No: Go to step 2
2. Try to give everyone except 1 person 8.
- Do we have enough in the budget? No: Invalid solution, go to step 3
Yes: How much is left over for the 1 person?
Is it 4 or 0?
No: You have found the solution: (giftees - 1)
Yes: Invalid solution, go step 3
3. Try to give everyone except 2 people 8.
- Do we have enough in the budget? No: Invalid solution, go to step 4
Yes: How much is left over for the 2 people?
Is it less than 2 (i.e. enough for 1 each)
No: You have found the solution: (giftees - 2)
Yes: Invalid solution, go to step 4
4. Try to give everyone except 3 people 8.
- Do we have enough in the budget? No: Invalid solution, go to step 5
Yes: How much is left over for the 3 people?
Is it less than 3 (i.e. enough for 1 each)
No: You have found the solution:(giftees - 3)
Yes: Invalid solution, go to step 5
... keep going until you give nobody 8
Some more test cases for you
luckyMoney(64, 8) == 8 e.g. [8,8,8,8,8,8,8,8]
luckyMoney(65, 10) == 7 e.g. [8,8,8,8,8,8,8,7,1,1]
luckyMoney(66, 10) == 8 e.g. [8,8,8,8,8,8,8,8,1,1]
luckyMoney(100, 1) == 1 e.g. [8]
This is a sample of LukyMoney function in C#:
public static int LuckyMoney(int money, int giftees)
{
decimal fortune = 8;
int dist = (int)(money / fortune);
if((giftees - dist) == 1)
return dist - 1;
if(dist > giftees)
return giftees;
return dist;
}
const luckyMoney = (money, giftees) => {
for(let i = 0; i <= giftees; i++){
const moneyleft = money - (giftees-i)*8;
if (i=== 0){
if (moneyleft >= 0){
return giftees-i
}
}
else if(i===1){
if (moneyleft>0 && moneyleft!=4){
return giftees - i
}
}
else{
if (moneyleft>=i){
return giftees -i
}
}
}
}
I think no loop is needed.
In C/ C++ :
size_t lucky_money(size_t money, size_t giftees) {
size_t max_giftees = (money / 8);
if (max_giftees < giftees) {
size_t rest_money = (money % 8);
size_t rest_giftees = (giftees - max_giftees);
// Subtract one giftee if the rest of money is not enough
return (((rest_giftees != 1) || (rest_money != 4))? (max_giftees + ((rest_money < rest_giftees)? -1: 0)): (0 /* dead */));
} else {
return giftees;
}
}
In JavaScript
function lucky_money(money, giftees) {
let max_giftees = Math.floor(money / 8);
if (max_giftees < giftees) {
let rest_money = (money % 8);
let rest_giftees = (giftees - max_giftees);
// Subtract one giftee if the rest of money is not enough
return (((rest_giftees !== 1) || (rest_money !== 4))? (max_giftees + ((rest_money < rest_giftees)? -1: 0)): (0 /* dead */));
} else {
return giftees;
}
}
console.log('inputs: 12 2, result: ', lucky_money( 12, 2)); // 8 + 4 (1 giftee) -> dead, 0
console.log('inputs: 24 4, result: ', lucky_money( 24, 4)); // 2*8 + 8 (2 giftees) -> 2
console.log('inputs: 7 2, result: ', lucky_money( 7, 2)); // 7 (money) < 8 -> 0
console.log('inputs: 64 9, result: ', lucky_money( 64, 9)); // 7*8 + 8 (2 giftees) -> 7
console.log('inputs: 60 8, result: ', lucky_money( 60, 8)); // 7*8 + 4 (1 giftee) -> dead, 0
console.log('inputs: 64 8, result: ', lucky_money( 64, 8)); // 8*8 -> 8
console.log('inputs: 65 10, result: ', lucky_money( 65, 10)); // 7*8 + 9 (3 giftees) -> 7
console.log('inputs: 66 10, result: ', lucky_money( 66, 10)); // 8*8 + 2 (2 giftees) -> 8
console.log('inputs: 100 1, result: ', lucky_money(100, 1)); // 1*8 + 92 (0 giftee) -> 1
60, 8
should be 6 and not 0!
6 * 8 = 48 and the remaining 2 giftee's will get any amount in the remaining 12(6/6)
object Solution extends App {
def f (num: Int, arr: List [Int]): List [List [Int]] =
arr.flatMap (List.fill (num) (_)).combinations (num).toList
def getDons (bd: Int, nf: Int): Int = {
var dist = (8 until budget + 1 by 8).toList
println (dist)
if (dist.length >= nbFils) return nbFils
while (dist.length > 0) {
var restBdTmp = budget - dist.last
println ("rest is : " + restBdTmp)
var restFils = nbFils - dist.length
println ("remaining childs : " + restFils)
var listP = (0 until restBdTmp + 1 by 1).toList
println("choices : " + listP)
println("combinations : "+f (restFils, listP))
var filterF = f (restFils, listP).filter (x =>
x.sum == restBdTmp && !x.contains (4) && !x
.contains (0)) // .filter(i => i.foreach{o => o!=4 && o != 0}
println (filterF)
if (filterF.length != 0) return dist.length
dist = dist.dropRight (1)
}
return 0
}
val budget = 100
val nbFils = 1
println (getDons (budget, nbFils))
}
return $money - $giftees < 7 ? 0 : (($money - $giftees) % 7 === 3 && $giftees - ((int)(($money - $giftees) / 7)) === 1 ? ((int)(($money - $giftees) / 7)) - 1 : min(((int)(($money - $giftees) / 7)), $giftees));

Grading Students in JS with recursion - Range Error

I was trying to work on this hackerrank problem.
Every student receives a grade in the inclusive range from
0-100 to .
Any less than 38 is a failing grade.
Sam is a professor at the university and likes to round each student's according to these rules:
If the difference between grade the and the next multiple of
5 is less than 3, round up to the next multiple of 5. If the value of grade is less than 38, no rounding occurs as the
result will still be a failing grade.
Given the initial value of for each of Sam's students, write code to
automate the rounding process.
My code is:
function gradingStudents(grades) {
const roundup = y => y + 1;
{
if ( grades < 38 || grades % 5 === 0) return grades;
else if ( grades % 5 < 4 && grades % 5 !== 0) return roundup(grades);
}
{
if (roundup % 5 === 0) return roundup;
else { gradingStudents(roundup + 1) }
}
}
gradingStudents(38) // -> 39
I tried to use Math.ceil(grades) inside the variable roundup but output didnt change. So, when you invoke the function with a number that is not before a multiple of 5 (e.g. 43) it returns the proceeding number. However, if it is the number before a multiple of 5 it gives a range error. "maximum call stack size reached."
As far as I got, the code doesnt proceed to the second part. Even if it did, I am not sure if it would fetch the current value of the function roundup when dealing with if statements in the second block.
What do I dont get in here?
Also, this is actually meant for an array output but since I am a beginner I am pretty much okay with this one for the start as well :D .
Javascript solution:
function gradingStudents(grades) {
return grades.map((grade) => {
if (grade > 37) {
const offset = 5 - (grade % 5);
if (offset < 3) {
grade += offset;
}
}
return grade;
});
}
Try this:
function gradingStudents(grades) { //input: 43
var finalGrade;
if(grade < 38)
return grades;
else{
var gradeDif = grades % 5; //3
if(gradeDif > 3){
return grades;
}
else {
return grades + (5 - gradeDif); //Output: 45
}
}
}
One solution calculates the next multiple of 5 no bigger than the grade and uses that value to test whether or not to round up (next5 - grade < 3).
We write a simple function to round an individual grade and then for a list of grades use .map with that function.
const roundGrade = (grade) => {
const next5 = 5 * Math.ceil (grade / 5)
return (grade < 38) ? grade : (next5 - grade < 3) ? next5 : grade
}
const gradingStudents = (grades) =>
grades .map (roundGrade)
console .log (gradingStudents ([73, 67, 38, 33]))
Note that, like most solutions to this problem, no recursion is needed.
1-Use the Array.prototypt.map according to the question logic.
const gradingStudents = (grades) => grades
.map(n => (n >= 38 && n % 5 >= 3)?(n + ( 5 - ( n % 5 ) )):n )
let result = gradingStudents([0,25,38,56,89,77,78,57,58])
console.log(result)
My solution is this
function gradingStudents(grades) {
grades.map((grade,i)=>{
if(grade >= 38){
let fg = (grade/5).toString().split('.');
if(fg[1]>5){
grades[i]=((parseInt(fg[0],10)+1) * 5);
};
}
});
return grades;
}
console.log(gradingStudents([73,67,38,33]));
my solution:
function gradingStudents(grades) {
return grades.map(function(grade) {
return (grade >= 38 && grade % 5 >= 3) ? grade + 5 - (grade % 5) : grade;
});
}

Smallest Common Multiple Code produces the wrong answer on one array

[edit]
I should clarify, I am attempting to find the smallest common multiple of a range of numbers. Sorry about that. I have attempted another solution but I still run into an incorrect answer on the last array [23, 18].
function smallestCommons(arr) {
arr = arr.sort(function (a, b) { return a - b; });
var count = 1;
for (var i = arr[0]; i <= arr[1]; i++) {
if (count % i !== 0) {
i = arr[0];
count++;
}
}
return count;
}
smallestCommons([23,18]);
My solution produces 2018940 when it should be 6056820
Your endless loop is becouse of your inner for loop which starts at the value 19 and runs to 22
414 (smallestMultiple of 18 & 23) % 19 == 15
414 % 20 = 14
414 % 21 = 15
414 % 22 = 18
which leads to your statement if(count % i == 0) being false and your for loop goes on with 415 416 ...
if u want to get the
least common multiple
var isSmallestMultipe = 0;
while(isSmallestMultiple == 0)
{
for(var i = 1; i <= arr[1]; i+)
{
if((arr[0]*i) % arr[1] == 0)
{
isSmallestMultiple = arr[0] * i;
}
}
}

Why is recursive wordsearch solver missing five words yet finding the other 47?

I'm creating a recursive wordsearch app which appears (to my amateur eye) correct yet is missing five of the fifty three words. The words may be hidden left to right, right to left, up, down or diagonally. I want the console to output the found word, x and y coordinates in the puzzle, and direction. I have looked through the code tirelessly and can't seem to find the problem. Please help!
The missing words are:
2: Backup
29: LCD
40: Power Supply
44: Scanner
53: Wireless
Here's the code:
I'm loading the puzzle and word list from textareas:
<textarea name="wordsearch" id="wordsearch" style="display:none">
TPIRCSAVAJLEXIPIGE
LIAMEMORYMMOUSENIL
CRABKSATXINUYHSTFG
DNDIRECTORYETAOEOO
POWERSUPPLYNIRFRLO
UCOASAEVASCCRETNDG
KIROPKTYPSHRUWWEEL
CDDECPREEAHYCAATRM
ANRIMALLTDRPERREAT
BOLENMEIEKETSEEPHH
RCKIPRAFCVRIIRSULM
EEBEIARRIABOOTMBOR
NSTWRAPRGRTNWBINGO
NOOSGNDLOODINTIOIS
ANGMAKAULARAOTEANR
CAEASPTLTAIPONRNDU
SNFIREWALLWREIKOOC
TFDPRDHTOOTEULBYTE</textarea>
<textarea name="wordlist" id="wordlist" style="display:none">
Application
Backup
Binary
Bluetooth
Boot
Byte
Chat
Click
Cookie
Cursor
Data
Defragment
Directory
Disk drive
DOS
Drag
Email
Encryption
File
Firewall
Folder
GIF
Google
HTML
Icon
Internet
JavaScript
Kernal
LCD
Login
Memory
Monitor
Mouse
Nanosecond
Network
Partition
Paste
PDF
Pixel
Power Supply
Programmer
Router
Save As
Scanner
Security
ShareWare
Software
Spam
Taskbar
Thumbnail
UNIX
Wallpaper
Wireless</textarea>
<script src="wordsearch.js" type="text/javascript"></script>
And the javascript:
(function() {
var puzzle = [];
var rows = 0;
var columns = 0;
var words = [];
var foundWordsArray = [];
var foundWordsObj = {
word: "",
coordinates: {
x: 0,
y: 0
},
direction: ""
};
window.onload = function() {
puzzle = document.getElementById("wordsearch").value.split("\n").map(function(p) {
return p.toUpperCase();
});
words = document.getElementById("wordlist").value.split("\n").map(function(w) {
return w.toUpperCase().replace(/\s/g, '');
});
rows = puzzle.length;
columns = puzzle[0].length;
solvePuzzle();
};
function solvePuzzle() {
var wFound = []; // list of words that were found
var res = false; // was word found in any direction
var wL = words.length;
// console.log(wL);
var i = 0; // index for the words
var j = 0; // index for the puzzle rows
var k = 0; // index for the puzzle columns
var fChar = ''; // first character
for (i = 0; i < wL; ++i) {
fChar = words[i].charAt(0);
wordFound:
for (j = 0; j < rows; ++j) {
for (k = 0; k < columns; ++k) {
if (fChar == puzzle[j].charAt(k + 1)) {
// found first character
//left
res = findWordLeft(words[i], 1, words[i].length, j, k + 1);
if (false !== res) {
// console.log(i + 1, words[i], (k + 2), (j + 1), "RL");
break wordFound; // found a word, break to wordFound
}
//Right
res = findWordRight(words[i], 1, words[i].length, j, k + 1);
if (false !== res) {
// console.log(i + 1, words[i], (k + 2), (j + 1), "LR");
break wordFound; // found a word, break to wordFound
}
//Up
res = findWordUp(words[i], 1, words[i].length, j, k + 1);
if (false !== res) {
// console.log(i + 1, words[i], (k + 2), (j + 1), "U");
break wordFound; // found a word, break to wordFound
}
//Down
res = findWordDown(words[i], 1, words[i].length, j, k + 1);
if (false !== res) {
// console.log(i + 1, words[i], (k + 2), (j + 1), "D");
break wordFound; // found a word, break to wordFound
}
//UpLeft
res = findWordUpLeft(words[i], 1, words[i].length, j, k + 1);
if (false !== res) {
// console.log(i + 1, words[i], (k + 2), (j + 1), "DUL");
break wordFound; // found a word, break to wordFound
}
//UpRight
res = findWordUpRight(words[i], 1, words[i].length, j, k + 1);
if (false !== res) {
// console.log(i + 1, words[i], (k + 2), (j + 1), "DUR");
break wordFound; // found a word, break to wordFound
}
//DownLeft
res = findWordDownLeft(words[i], 1, words[i].length, j, k + 1);
if (false !== res) {
// console.log(i + 1, words[i], (k + 2), (j + 1), "DDL");
break wordFound; // found a word, break to wordFound
}
//DownRight
res = findWordDownRight(words[i], 1, words[i].length, j, k + 1);
if (false !== res) {
// console.log(i + 1, words[i], (k + 2), (j + 1), "DDR");
break wordFound; // found a word, break to wordFound
}
}
}
}
}
}
function findWordLeft(word, posW, wordL, j, k) {
var result = false;
if (posW == wordL) { // check if all characters were found
return true;
}
if (k > 0 && word.charAt(posW) == puzzle[j].charAt(k - 1)) {
result = findWordLeft(word, posW + 1, wordL, j, k - 1);
if (result !== false) {
return new Array(j, k - 1);
}
}
return result;
}
function findWordRight(word, posW, wordL, j, k) {
var result = false;
if (posW == wordL) { // check if all characters were found
return true;
}
if (k < columns && word.charAt(posW) == puzzle[j].charAt(k + 1)) {
result = findWordRight(word, posW + 1, wordL, j, k + 1);
if (result !== false) {
return new Array(j, k + 1);
}
}
return result;
}
function findWordUp(word, posW, wordL, j, k) {
var result = false;
if (posW == wordL) { // check if all characters were found
return true;
}
if (0 <= (j - 1) && word.charAt(posW) == puzzle[j - 1].charAt(k)) {
result = findWordUp(word, posW + 1, wordL, j - 1, k);
if (result !== false) {
return new Array(j - 1, k);
}
}
return result;
}
function findWordDown(word, posW, wordL, j, k) {
var result = false;
if (posW == wordL) { // check if all characters were found
return true;
}
if (rows > (j + 1) && word.charAt(posW) == puzzle[j + 1].charAt(k)) {
result = findWordDown(word, posW + 1, wordL, j + 1, k);
if (result !== false) {
return new Array(j + 1, k);
}
}
return result;
}
function findWordUpLeft(word, posW, wordL, j, k) {
var result = false;
if (posW == wordL) { // check if all characters were found
return true;
}
if (0 < k && 0 < j && word.charAt(posW) == puzzle[j - 1].charAt(k - 1)) {
result = findWordUpLeft(word, posW + 1, wordL, j - 1, k - 1);
if (result !== false) {
return new Array(j - 1, k - 1);
}
}
return result;
}
function findWordUpRight(word, posW, wordL, j, k) {
var result = false;
if (posW == wordL) { // check if all characters were found
return true;
}
if (columns > k && 0 < j && word.charAt(posW) == puzzle[j - 1].charAt(k + 1)) {
result = findWordUpRight(word, posW + 1, wordL, j - 1, k + 1);
if (result !== false) {
return new Array(j - 1, k + 1);
}
}
return result;
}
function findWordDownLeft(word, posW, wordL, j, k) {
var result = false;
if (posW == wordL) { // check if all characters were found
return true;
}
if (rows > (j + 1) && 0 < k && word.charAt(posW) == puzzle[j + 1].charAt(k - 1)) {
result = findWordDownLeft(word, posW + 1, wordL, j + 1, k - 1);
if (result !== false) {
return new Array(j + 1, k - 1);
}
}
return result;
}
function findWordDownRight(word, posW, wordL, j, k) {
var result = false;
if (posW == wordL) { // check if all characters were found
return true;
}
if (rows > (j + 1) && columns > k && word.charAt(posW) == puzzle[j + 1].charAt(k + 1)) {
result = findWordDownRight(word, posW + 1, wordL, j + 1, k + 1);
if (result !== false) {
return new Array(j + 1, k + 1);
}
}
return result;
}
})();
Here is what I get from the console:
1 "APPLICATION" 4 6 "DDR"
3 "BINARY" 3 12 "DUR"
4 "BLUETOOTH" "RL" 15 18
5 "BOOT" 11 12 "LR"
6 "BYTE" 15 18 "LR"
7 "CHAT" 12 6 "DDL"
8 "CLICK" 2 11 "DUR"
9 "COOKIE" "RL" 18 17
10 "CURSOR" 18 17 "U"
11 "DATA" 11 14 "DDL"
12 "DEFRAGMENT" 10 9 "DDL"
13 "DIRECTORY" 3 4 "LR"
14 "DISKDRIVE" 3 18 "DUR"
15 "DOS" 3 8 "DUR"
16 "DRAG" 6 18 "DUL"
17 "EMAIL" "RL" 5 2
18 "ENCRYPTION" 12 4 "D"
19 "FILE" 8 11 "U"
20 "FIREWALL" 3 17 "LR"
21 "FOLDER" 17 3 "D"
22 "GIF" 17 1 "D"
23 "GOOGLE" 18 6 "U"
24 "HTML" 18 10 "U"
25 "ICON" 2 7 "U"
26 "INTERNET" 16 1 "D"
27 "JAVASCRIPT" "RL" 10 1
28 "KERNAL" 3 11 "DDR"
30 "LOGIN" 17 11 "D"
31 "MEMORY" 4 2 "LR"
32 "MONITOR" 18 11 "DDL"
33 "MOUSE" 11 2 "LR"
34 "NANOSECOND" 2 17 "U"
35 "NETWORK" 16 16 "DUL"
36 "PARTITION" 9 7 "DDR"
37 "PASTE" 6 16 "DUL"
38 "PDF" "RL" 4 18
39 "PIXEL" "RL" 15 1
41 "PROGRAMMER" 12 16 "DUL"
42 "ROUTER" 10 13 "DDL"
43 "SAVEAS" "RL" 10 6
45 "SECURITY" 13 10 "U"
46 "SHAREWARE" 14 2 "D"
47 "SOFTWARE" 15 3 "D"
48 "SPAM" 15 11 "DUR"
49 "TASKBAR" "RL" 8 3
50 "THUMBNAIL" 18 9 "DDL"
51 "UNIX" "RL" 12 3
52 "WALLPAPER" 11 17 "DUL"
There seems to be something off with the way you indexing or the way you check for the boundaries. To be honest, I can't exactly tell you what the problem is, but I have a working version which is much shorter and with less code repetition. Maybe you can take something from that.
function solvePuzzle() {
// list of words that were found
var wFound = [];
console.log("Number of words:", words.length);
// loop over words
for (var i = 0; i < words.length; ++i) {
var fChar = words[i].charAt(0);
wordFound:
// loop over characters
for (var j = 0; j < rows; ++j) {
for (var k = 0; k < columns; ++k) {
// check first character
if (fChar == puzzle[j].charAt(k)) {
// iterate over all 9 directions
for (var dj = -1; dj <= 1; dj++) {
for (var dk = -1; dk <= 1; dk++) {
// skip invalid direction
if (dj == 0 && dk == 0) continue;
// try to find word
if (findWord(words[i], 0, j, k, dj, dk)) {
console.log(i + 1, words[i], k + 1, j + 1, getDirectionString(dj, dk));
// found a word
wFound.push(words[i]);
break wordFound;
}
}
}
}
}
}
}
console.log("Number of words found:", wFound.length);
}
function findWord(word, posW, j, k, dj, dk) {
// check if all characters were found
if (posW == word.length) return true;
// check if position is outside the boundaries
if (j < 0 || j >= rows || k < 0 || k >= columns) return false;
// check if current character fails to match the word
if (word.charAt(posW) != puzzle[j].charAt(k)) return false;
// check next character
return findWord(word, posW + 1, j + dj, k + dk, dj, dk);
}
function getDirectionString(dj, dk) {
switch (dj) {
case -1: switch (dk) { case -1: return "DUL"; case 0: return "U"; case 1: return "DUR"; } break;
case 0: switch (dk) { case -1: return "RL"; case 1: return "LR"; } break;
case 1: switch (dk) { case -1: return "DDL"; case 0: return "D"; case 1: return "DDR"; } break;
}
return "invalid";
}
The output is:
Number of words: 53
1 "APPLICATION" 4 6 "DDR"
2 "BACKUP" 1 10 "U"
3 "BINARY" 3 12 "DUR"
4 "BLUETOOTH" 15 18 "RL"
5 "BOOT" 11 12 "LR"
6 "BYTE" 15 18 "LR"
7 "CHAT" 12 6 "DDL"
8 "CLICK" 2 11 "DUR"
9 "COOKIE" 18 17 "RL"
10 "CURSOR" 18 17 "U"
11 "DATA" 11 14 "DDL"
12 "DEFRAGMENT" 10 9 "DDL"
13 "DIRECTORY" 3 4 "LR"
14 "DISKDRIVE" 3 18 "DUR"
15 "DOS" 3 8 "DUR"
16 "DRAG" 6 18 "DUL"
17 "EMAIL" 5 2 "RL"
18 "ENCRYPTION" 12 4 "D"
19 "FILE" 8 11 "U"
20 "FIREWALL" 3 17 "LR"
21 "FOLDER" 17 3 "D"
22 "GIF" 17 1 "D"
23 "GOOGLE" 18 6 "U"
24 "HTML" 18 10 "U"
25 "ICON" 2 7 "U"
26 "INTERNET" 16 1 "D"
27 "JAVASCRIPT" 10 1 "RL"
28 "KERNAL" 3 11 "DDR"
29 "LCD" 1 2 "D"
30 "LOGIN" 17 11 "D"
31 "MEMORY" 4 2 "LR"
32 "MONITOR" 18 11 "DDL"
33 "MOUSE" 11 2 "LR"
34 "NANOSECOND" 2 17 "U"
35 "NETWORK" 16 16 "DUL"
36 "PARTITION" 9 7 "DDR"
37 "PASTE" 6 16 "DUL"
38 "PDF" 4 18 "RL"
39 "PIXEL" 15 1 "RL"
40 "POWERSUPPLY" 1 5 "LR"
41 "PROGRAMMER" 12 16 "DUL"
42 "ROUTER" 10 13 "DDL"
43 "SAVEAS" 10 6 "RL"
44 "SCANNER" 1 17 "U"
45 "SECURITY" 13 10 "U"
46 "SHAREWARE" 14 2 "D"
47 "SOFTWARE" 15 3 "D"
48 "SPAM" 15 11 "DUR"
49 "TASKBAR" 8 3 "RL"
50 "THUMBNAIL" 18 9 "DDL"
51 "UNIX" 12 3 "RL"
52 "WALLPAPER" 11 17 "DUL"
Number of words found: 52

Pagination algorithm working incorrectly

I've got a fairly simple pagination algorithm here but it's not working the way I'd like it to.
Currently it's displaying like this
1 2 3 ... 33 34 35 [36] 37 38 ... 47 48 49 50
When it should be displaying like this
1 2 3 ... 33 34 35 [36] 37 38 39 ... 48 49 50
Here's my code, I wrote it very quickly. It also seems to continuously run (The loop doesn't stop) but I've no idea why.
$(function(){
var pages = 50; //Total number of pages
var current = 36; //The current page we are on
var before = 3; //Number of links to display before current
var after = 3; //Same as above but after
var start = (current - before); //The number of the first link
var end = (current + after); //Number of the end link
for(var i = 1; i <= pages; i++){
if(i == (before + 1)){
i = start;
document.write('...');
}
else if(i == (current + after)){
i = (pages - after);
document.write('...');
}
if(i == current){
document.write(' ['+i+'] ');
}
else{
document.write(' '+i+' ');
}
}
});
If (current + after) > (pages - after) and (current + after) < pages then this code will run forever because of:
else if(i == (current + after)){
i = (pages - after);
document.write('...');
}
Each time i reaches current + after, it will be reduced to pages - after and that cycle will continue indefinitely
Please fix after to after + 1 in 2 places in all places in your loop where you use it.
Also, I am not sure your code will work correctly for edge cases (e.g. where current == 2) - you may want to test that
current + after is 39 (36 + 3) here, so no wonder it displays "..." instead of 39, increase "after" by 1 to fix this
after looking at the code for several minutes, I don't have a clue why it should run forever :) Have you tried writing "i" to the console to check what values it takes and why it never reaches its "final value"?
There is a reason why arrays used zero-based indexing in most languages: the math is just simpler. In your case, since you obviously can't use zero-based indexing, you'll just have to fix the off-by-one errors:
else if(i == (current + after + 1)){
i = (pages - after + 1);
document.write('...');
}
The following algorithm gives 5 pages around the current page
Example:
- [X] is the current page
- In this case the total pages are 20
<[1] 2 3 4 5>
<1 [2] 3 4 5>
<1 2 [3] 4 5>
<2 3 [4] 5 6>
... numbers in between ...
<15 16 [17] 18 19>
<16 17 [18] 19 20>
<16 17 18 [19] 20>
<16 17 18 19 [20]>
Or in case total pages are less than 5, say 3...
The results look like
<[1] 2 3>
And so on.
function (page, totalPages) {
var leftBoundry = Math.max(1, page - 2)
var rightBoundry = Math.min(totalPages, page + 2)
var arr = []
var emptyRight = 2 - (rightBoundry - page)
var emptyLeft = 2 - (page - leftBoundry)
leftBoundry = Math.max(1, leftBoundry - emptyRight)
rightBoundry = Math.min(totalPages, rightBoundry + emptyLeft)
for (var i = leftBoundry; i <= rightBoundry; i++) {
arr.push(i)
}
return arr;
}
.

Categories

Resources