28/12/2021

10 Jours de JavaScript - HackerRank (2/3)

Day 4: Create a Rectangle Object (28.12.2021)

En JS un objet est un ensemble de propriétés. Une propriété est une association entre un nom et une valeur.

function Rectangle(a, b) {
    this.length = a;
    this.width = b;
    this.perimeter = 2 * (a + b);
    this.area = a * b;
}

Day 4: Count Objects (28.12.2021)

function getCount(objects) {
    let count = 0;
    objects.forEach(o => {
        if (o.x === o.y) count++;
    });
    return count;
}

Day 4: Classes (28.12.2021)

La classe possède un constructeur. Il permet de créer d'autres objets de même type.

class Polygon {
    
    constructor(arrays) {
        this.arrays = arrays;
    }
    
    perimeter() {
        let sum = 0;
        this.arrays.forEach(a => {
            sum += a;
        });
        return sum;
    }
}

Day 5: Inheritance (29.12.2021)

  • Une classe peut hériter d'une classe mère en utilisant le mot clé extends
  • Une méthode peut être ajoutée au prototype d'une classe. C'est aussi possible d'ajouter directement la méthode dans la classe définie.
class Rectangle {
    constructor(w, h) {
        this.w = w;
        this.h = h;
    }
}

Rectangle.prototype.area = function () {
    return this.w * this.h;
}

class Square extends Rectangle {
    constructor(w) {
        super(w, w);
    }
}

Day 5: Template Literals (29.12.2021)

Le template literal (`.....`) permet d'écrire des chaînes de caractères sur plusieurs lignes. Il permet aussi de profiter du string interpolation (ex: ${name}).

NB: Ce challenge est assez bizarre. Les instructions ne sont pas claires et on ne manipule pas réellement le template litteral lors du codage.

function sides(literals, ...expressions) {
    let [A, P] = [expressions[0], expressions[1]];
    let s1 = (P + Math.sqrt(Math.pow(P, 2) - 16 * A)) / 4;
    let s2 = (P - Math.sqrt(Math.pow(P, 2) - 16 * A)) / 4;
    return [s1, s2].sort();
}

Day 6: Arrow Functions (30.12.2021)

Les fonctions fléchées possèdent une syntaxe courte. 

function modifyArray(nums) {
    let result = [];
     nums.forEach(num => {
        num % 2 == 0 ? result.push(num * 2) : result.push(num * 3);
    });
    return result;
}

Day 6: Bitwise Operators (30.12.2021)

  • En JS, l'opération de type ET Logique (AND) au niveau du bit (bitwise operation) se fait en utilisant l'opérateur &. Ex: 1 & 2 correspond niveau bit à 01 AND 10 ce qui donne 00 (en base 2) et 0 (en base 10).
  • J'ai trouvé ce challenge assez intéressant parce que j'ai appris lors du codage que Math.max(...r) (où r est un tableau, ...r est la décomposition du tableau en éléments distincts)  ne marche que lorsque ce tableau contient peu d'éléments. Lorsqu'on a plus d'une centaine d'éléments, alors on obtient un Runtime Error (cette opération doit être complexe et gourmande en mémoire).
function getMaxLessThanK(n, k) {
   let r = [];
    for (let i=1; i<=n; i++) {
        for (let j=i+1; j<=n; j++) {
            if ((i & j) < k) {
                r.push(i & j);
            }
        }
    }
    //return Math.max(...r);
    let max = r[0];
    for (let el of r) {
        if (el > max) max = el;
    }
    return max;
}

Day 6: JavaScript Dates (30.12.2021)

// The days of the week are: "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
function getDayName(dateString) {
    let dayName;
    let theDay = new Date(dateString);
    const dayNumber = theDay.getDay();
    switch(dayNumber) {
        case 0:
            dayName = "Sunday";
            break;
        case 1:
            dayName = "Monday";
            break;
        case 2: 
            dayName = "Tuesday";
            break;
        case 3:
            dayName = "Wednesday";
            break;
        case 4:
            dayName = "Thursday";
            break;
        case 5:
            dayName = "Friday";
            break;
        case 6:
            dayName = "Saturday";
            break;
        default:
            throw Error("This day does not exist !");
    }

Day 7: Regular Expressions I (31.12.2021)

Ce challenge aborde les regex (expressions régulières). Cela mérite un tutoriel à part entière.

//  ^ => first item matches:
// () => stores matching value captured within
// [aeiou] => matches any of the characters in the brackets
// . => matches any character:
// + => for 1 or more occurrances (this ensures str length > 3)
// \1 => matches to previously stored match. 
    // \2 looks for matched item stored 2 instances ago 
    // \3 looks for matched item stored 3 ago, etc

//  $ ensures that matched item is at end of the sequence

function regexVar() {
    let re = /^([aeiou]).+\1$/;
    return re;
}

function main() {
    const re = regexVar();
    const s = readLine();
    
    console.log(re.test(s));
}

Day 7: Regular Expressions II (01.01.2022)

1er jour de la nouvelle année - Joyeuse fête à toutes et à tous.

function regexVar() {
 
    let re = /^(Mr|Mrs|Ms|Dr|Er)(\.)([a-zA-Z])+$/;
    return re;
}

Day 7: Regular Expressions III (02.01.2022)

Ce challenge se base sur les flags. Par exemple g pour un match global, i pour ignorer la casse (majuscule, minuscule).

function regexVar() {
    
    let re = /[0-9]+/g;
    return re;
}


24/12/2021

10 Jours de JavaScript - HackerRank (1/3)

Les fêtes de fin d'année sont là - demain Noël et dans 8 jours la nouvelle année. Actuellement, je dispose de quelques slots de libre dans mon timetable. Alors pourquoi ne pas en profiter - pour le fun - et faire le challenge 10 Days of JavaScript du site de coding HackerRank. Je me rappelle avoir débuté ce challenge en Octobre 2019 mais je ne l'avais point terminé. L'ancien dépôt git se trouve ici. Je ne l'avais pas terminé parce que j'étais pris pas de nombreux projets professionnels et donc peu de temps à y consacrer. 

Bien évidemment je code déjà en JavaScript (JS) depuis plusieurs années, mais j'ai décidé aujourd'hui de relever ce challenge. Peut-être qu'il m'apprendra une ou deux notions que j'avais oubliée(s) ou que je ne connaissais pas déjà . Voyons voir! Le nouveau dépôt git se trouve ici

Day 0: Hello, World! (24.12.2021)

Le Jour 0 est consacré à l'affichage de texte (string) en utilisant la fonction console.log().

function greeting(parameterVariable) {
    console.log('Hello, World!');
    console.log(parameterVariable);
}

Day 0: Data Types (25.12.2021)

Les entiers et les décimaux sont de type  Number. Les chaînes de caractères sont de type String.

function performOperation(secondInteger, secondDecimal, secondString) {
    const firstInteger = 4;
    const firstDecimal = 4.0;
    const firstString = 'HackerRank ';

    console.log(firstInteger + Number(secondInteger));

    console.log(firstDecimal + Number(secondDecimal));
    
    console.log(firstString + secondString);
    
}

Day 1: Arithmetic Operators (25.12.2021)

L'addition se fait avec l'opérateur + et la multiplication avec l'opérateur *.

function getArea(length, width) {
    let area;
    area = length * width;
    
    return area;
}

function getPerimeter(length, width) {
    let perimeter;
    perimeter = 2 * (length + width);
    
    return perimeter;
}

Day 1: Functions (25.12.2021)

Une fonction peut retourner une valeur ou aucune valeur (dans ce cas c'est une procédure).

function factorial(n) {
    if (n === 0 || n === 1) return 1;
    
    return n * factorial(n-1);
}

En ce Day 1, qui correspond au 25 Décembre, Je souhaite un Joyeux Noël à tous et à toutes !

Day 1: Let and Const (26.12.2021)

Le mot let est utilisé pour définir une variable. Le mot const est utilisé pour définir une constante. Souvent la variable constante est écrite en majuscule.

function main() {

    let r = readLine();
    const PI = Math.PI;
    let area = PI * Math.pow(r, 2);
    let perimeter = 2 * PI * r;
    
    // Print the area of the circle:
    console.log(area);
    
    // Print the perimeter of the circle:
    console.log(perimeter);
}

Day 2: Conditional Statements: If-Else (26.12.2021)

La structure conditionnelle se fait en utilisant: if (condition1) {} else if (condition2) {} else {}.

function getGrade(score) {
    let grade;
    
    if (25 < score && score <= 30) grade = 'A';
    else if (20 < score && score <= 25) grade = 'B';
    else if (15 < score && score <= 20) grade = 'C';
    else if (10 < score && score <= 15) grade = 'D';
    else if (5 < score && score <= 10) grade = 'E';
    else if (0<= score && score <= 5) grade = 'F';
    
    return grade;
}

Day 2: Conditional Statements: Switch (26.12.2021)

Dans certains cas, au  lieu d'agencer plusieurs if ... else, on peut utiliser switch.

function getLetter(s) {
    let letter;
    
    switch(s.charAt(0)) {
        case 'a': case 'e': case 'i': case 'o': case 'u':
            letter = 'A';
            break;
        case 'b': case 'c': case 'd': case 'f': case 'g':
            letter = 'B';
            break;
        case 'h': case 'j': case 'k': case 'l': case 'm':
            letter = 'C';
            break;
        default: 
            letter = 'D';
        
    }
    
    return letter;
}

Day 2: Loops (26.12.2021)

On peut faire une boucle en utilisant for ou while. La méthode forEach permet de boucler sur une collection d'éléments.
 
function vowelsAndConsonants(s) {
    let vowels = ['a', 'e', 'i', 'o', 'u'];
    for (let i=0; i<s.length; i++) {
        let c = s.charAt(i);
        if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
        console.log(c);   
}
    
    for (let i=0; i<s.length; i++) {
        let c = s.charAt(i);
        if (c != 'a' && c != 'e' && c != 'i' && c !== 'o' && c !== 'u') 
        console.log(c);   
    }  
}

function vowelsAndConsonants(s) {
    let vowels = [];
    let consonants = [];
    let newS = [...s];
    newS.forEach(v => {
        if (v == 'a' || v == 'e' || v == 'i' || v == 'o' || v == 'u')                            
        { vowels.push(v); }  
        else { consonants.push(v); }
    });
    
    vowels.forEach(v => console.log(v));
    consonants.forEach(v => console.log(v));
    
}

Day 3: Arrays (27.12.2021)

L'opérateur ... permet de déstructurer (décomposer) un tableau en des variables distinctes. 

function getSecondLargest(nums) {
    let max = Math.max(...nums);
    let newNums = nums.filter(e => e!=max);
    return Math.max(...newNums);
}

Day 3: Try, Catch, and Finally (27.12.2021)

function getSecondLargest(nums) {
    let max = Math.max(...nums);
    let newNums = nums.filter(e => e!=max);
    return Math.max(...newNums);
}

Day 3: Throw (27.12.2021)

function isPositive(a) { 
    if (a > 0) return "YES";
    else if (a == 0) throw Error("Zero Error");
    else throw Error("Negative Error");
}



21/12/2021

ResultSet: une erreur assez basique

Actuellement, je prépare des notes de cours sur le développement web avec Java. C'est l'occasion pour moi de revoir les opérations basiques d'accès aux bases de données avec l'API JDBC (Java DataBase Connectivity). Avec cette API, une requête SQL est traitée en cinq étapes:

  1. Etablir la connexion à la base de données.
  2. Créer le statement SQL (associé à la requête SQL: requête simple, préparée ou procédure stockée).
  3. Exécuter la requête SQL.
  4. Parcourir les résultats de la requête (ResultSet)
  5. Fermer la connexion
Dans mon cas, c'est au niveau du parcours des résultats (4) qu'une erreur s'est produite. Durant l'exécution de ces cinq étapes, deux exceptions doivent être levées: ClassNotFoundException et SQLException. Voici le code: 

public void persistBookObject(Book book) {  
    try {
          Class.forName(driverName); //pour charger le driver
          connection = DriverManager.getConnection(url, dbUsername, dbPassword);

          PreparedStatement stmt = connection.prepareStatement("SELECT DISTINCT COUNT(*) AS 
          NBR_PUBLISHER FROM PUBLISHER WHERE CODE = ?");
          stmt.setString(1, book.getPublisher().getCode());
          ResultSet rs = stmt.executeQuery();
          int ifPublisherExists = 0;
          ifPublisherExists = rs.getInt("NBR_PUBLISHER");
          System.out.println("INFO: " + ifPublisherExists);
          stmt.close();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
      		e.printStackTrace();
 		} finally {
      		try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
  }

Dans mon cas, l'exécution de ce code produit l'exception suivante:

java.sql.SQLException: Before start of result set
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63)
at com.mysql.cj.jdbc.result.ResultSetImpl.checkRowPos(ResultSetImpl.java:517)
at com.mysql.cj.jdbc.result.ResultSetImpl.getObject(ResultSetImpl.java:1314)
at com.mysql.cj.jdbc.result.ResultSetImpl.getInt(ResultSetImpl.java:822)
at com.mysql.cj.jdbc.result.ResultSetImpl.getInt(ResultSetImpl.java:843)
at service.BookStoreService.persistBookObject(BookStoreService.java:34)
at client.BookStoreClient.main(BookStoreClient.java:28)

En analysant cette exception et le code ci-dessus, je m'aperçois que l'erreur vient de l'accès au résultat produit par l'exécution de la requête SQL. Pour corriger cette erreur, il faudra donc parcourir le tableau des résultats renvoyé par l'exécution de la requête SQL. En terme simple, le ResultSet doit d'abord être parcouru. Puisqu'une seule valeur est renvoyée par la requête, il suffit de placer le curseur sur la prochaine valeur du ResultSet. Je dois donc faire: 

if (rs.next()) {
    ifPublisherExists = rs.getInt("NBR_PUBLISHER");
    System.out.println("INFO: " + ifPublisherExists);
}

En conclusion, le ResultSet est une interface importante fournit par l'API JDBC qui permet d'accéder aux résultats issus de l'exécution d'une requête SQL sur une base de données. Maîtriser cette interface permet d'accéder efficacement aux données recherchées. Voyons en détail cette interface dans un prochain post.