Categories
JavaScript Answers

How to Solve CyclicRotation Problem in JavaScript?

To solve the problem of rotating an array A by K positions to the right, we can follow a straightforward approach:

Steps to Approach

If A is empty (N = 0), return an empty array since there’s nothing to rotate.

If K is zero, return A as it is since no rotation is needed.

Since rotating an array N times where N is the length of the array results in the same array, the effective number of rotations K can be reduced to K % N. This is because rotating an array N times or any multiple of N results in the array itself.

To rotate the array to the right by K positions, the idea is to move the last K elements of A to the front and shift the rest to the right.

  • This can be achieved by creating a new array where the elements from A[N-K] to A[N-1] (last K elements) are placed at the beginning, followed by the elements from A[0] to A[N-K-1] (remaining elements).

Implementation in JavaScript

Here’s the implementation based on the outlined approach:

function solution(A, K) {
    const N = A.length;
    
    // Handle edge cases
    if (N === 0 || K === 0) {
        return A;
    }
    
    // Effective rotations
    K = K % N;
    
    // If no effective rotation needed
    if (K === 0) {
        return A;
    }
    
    // Create a new array for rotated result
    const rotatedArray = [];
    
    // Elements from A[N-K] to A[N-1] (last K elements)
    for (let i = N - K; i < N; i++) {
        rotatedArray.push(A[i]);
    }
    
    // Elements from A[0] to A[N-K-1] (first N-K elements)
    for (let i = 0; i < N - K; i++) {
        rotatedArray.push(A[i]);
    }
    
    return rotatedArray;
}

Handle cases where A is empty or K is zero directly to optimize and prevent unnecessary calculations.

By using K % N, we ensure that we only rotate as many times as necessary (K rotations effectively reduces to rotating K % N times).

We split the array into two parts.

Elements from A[N-K] to A[N-1] are appended first (last K elements).

Elements from A[0] to A[N-K-1] are appended next (remaining elements).

This approach effectively constructs the rotated array in a linear pass through the original array A.

This implementation ensures correctness by adhering to the problem requirements and handles all specified edge cases.

Categories
JavaScript Answers

How to Solve BinaryGap Problem with JavaScript?

To solve the problem of finding the longest binary gap in a given positive integer ( N ), we can follow these steps:

  1. Convert the integer ( N ) into its binary representation. In JavaScript, you can do this using toString(2) method.

  2. Traverse through the binary representation to identify sequences of consecutive zeros (‘0’). Keep track of the length of each sequence.

  3. As we identify these sequences, keep track of the maximum length encountered.

  4. Finally, return the length of the longest binary gap found. If no binary gaps are found, return 0.

Here’s the JavaScript implementation based on the described approach:

function solution(N) {
    const binaryString = N.toString(2); // Convert N to binary string
    let maxGapLength = 0;
    let currentGapLength = 0;
    let inGap = false;
    
    for (let i = 0; i < binaryString.length; i++) {
        if (binaryString[i] === '1') {
            if (inGap) {
                // We've encountered the end of a gap
                if (currentGapLength > maxGapLength) {
                    maxGapLength = currentGapLength;
                }
                currentGapLength = 0;
            }
            inGap = true;
        } else {
            if (inGap) {
                // We are inside a gap
                currentGapLength++;
            }
        }
    }
    
    return maxGapLength;
}

N.toString(2) converts ( N ) to its binary string representation.

Then we ierate through each character of the binary string

When encountering ‘1’, check if we were already in a gap (i.e., inGap is true). If so, this signifies the end of a gap, so update maxGapLength if the current gap is longer than previously recorded.

When encountering ‘0’, if we are in a gap (inGap is true), increment currentGapLength.

After the loop, ensure to check if the last recorded gap (if any) is the longest.

This algorithm is efficient with a time complexity of ( O(log N) ), where ( N ) is the integer input, due to the conversion to binary and subsequent traversal of its digits. This ensures it can handle the maximum input size within reasonable time constraints.

Categories
JavaScript Answers

How to Use the JavaScript Temporal API?

The Temporal API in JavaScript provides a modern way to handle dates and times, offering precise and flexible methods to work with temporal data.

We can use the functions that comes with Temporal API as follows:

Temporal.PlainDate

Temporal.PlainDate represents a calendar date without time or timezone information.

For example, we write

const date = Temporal.PlainDate.from('2023-07-07');
console.log(date.toString()); // 2023-07-07

const now = Temporal.Now.plainDateISO();
console.log(now.toString()); // Current date in YYYY-MM-DD format

const nextWeek = date.add({ days: 7 });
console.log(nextWeek.toString()); // 2023-07-14

const pastDate = date.subtract({ months: 1 });
console.log(pastDate.toString()); // 2023-06-07

Dates are returned in YYYY-MM-DD format.

Temporal.PlainTime

Temporal.PlainTime represents a time of day without a date or timezone.

For instance, we write:

const time = Temporal.PlainTime.from('14:30:00');
console.log(time.toString()); // 14:30:00

const now = Temporal.Now.plainTimeISO();
console.log(now.toString()); // Current time in HH:mm:ss.sss format

const later = time.add({ hours: 2 });
console.log(later.toString()); // 16:30:00

const earlier = time.subtract({ minutes: 15 });
console.log(earlier.toString()); // 14:15:00

Temporal.PlainDateTime

Temporal.PlainDateTime combines a date and a time without timezone information.

For example, we write

const dateTime = Temporal.PlainDateTime.from('2023-07-07T14:30:00');
console.log(dateTime.toString()); // 2023-07-07T14:30:00

const now = Temporal.Now.plainDateTimeISO();
console.log(now.toString()); // Current date and time in YYYY-MM-DDTHH:mm:ss.sss format

const nextHour = dateTime.add({ hours: 1 });
console.log(nextHour.toString()); // 2023-07-07T15:30:00

const pastWeek = dateTime.subtract({ weeks: 1 });
console.log(pastWeek.toString()); // 2023-06-30T14:30:00

Temporal.ZonedDateTime

Temporal.ZonedDateTime represents a date and time with a timezone.

For example, we write:

const zonedDateTime = Temporal.ZonedDateTime.from('2023-07-07T14:30:00+01:00[Europe/London]');
console.log(zonedDateTime.toString()); // 2023-07-07T14:30:00+01:00[Europe/London]

const now = Temporal.Now.zonedDateTimeISO();
console.log(now.toString()); // Current date and time with timezone

const newYorkTime = zonedDateTime.withZone('America/New_York');
console.log(newYorkTime.toString()); // 2023-07-07T09:30:00-04:00[America/New_York]

const later = zonedDateTime.add({ hours: 2 });
console.log(later.toString()); // 2023-07-07T16:30:00+01:00[Europe/London]

Temporal.Duration

Temporal.Duration represents a length of time.

For example, we can use it as follows:

const duration = Temporal.Duration.from({ days: 2, hours: 5 });
console.log(duration.toString()); // P2DT5H

const dateTime = Temporal.PlainDateTime.from('2023-07-07T14:30:00');
const newDateTime = dateTime.add(duration);
console.log(newDateTime.toString()); // 2023-07-09T19:30:00

const elapsed = newDateTime.since(dateTime);
console.log(elapsed.toString()); // P2DT5H

We use Temporal.Duration.from to create the duration of 2 days and 5 hours.

And we can calculate the elapsed time between 2 different date time with since.

Temporal.Calendar

Temporal.Calendar allows for working with different calendar systems.

For example, we write:

const isoDate = Temporal.PlainDate.from('2023-07-07');
const hebrewDate = isoDate.withCalendar('hebrew');
console.log(hebrewDate.toString()); // Hebrew calendar date

const convertedBack = hebrewDate.withCalendar('iso8601');
console.log(convertedBack.toString()); // 2023-07-07

We call withCalendar to convert dates to different calendar systems.

Temporal.TimeZone

Temporal.TimeZone provides information about time zones.

For example, we write

const timeZone = Temporal.TimeZone.from('America/New_York');
const dateTime = Temporal.PlainDateTime.from('2023-07-07T14:30:00');
const zonedDateTime = dateTime.toZonedDateTime(timeZone);
console.log(zonedDateTime.toString()); // 2023-07-07T14:30:00-04:00[America/New_York]

const nowInZone = Temporal.Now.zonedDateTime(timeZone);
console.log(nowInZone.toString()); // Current date and time in the specified time zone

to convert date times to date times with time zones with toZonedDateTime.

And we get the current date time with time zone with zonedDateTime.

The Temporal API offers a more robust and intuitive way to work with date and time in JavaScript, addressing many limitations of the existing Date object.

Categories
JavaScript

What’s New in ES2023?

ECMAScript 2023 (ES14) introduced several new features to improve JavaScript’s functionality and usability.

Here are the key updates with examples:

Array Find From Last

Array.prototype.findLast and Array.prototype.findLastIndex allow searching arrays from the end.

For example, we write:

const array = [1, 2, 3, 4, 5];
const found = array.findLast((element) => element % 2 === 1);
console.log(found); // 5

const foundIndex = array.findLastIndex((element) => element % 2 === 1);
console.log(foundIndex); // 4

Change Array by Copy

New methods like toSorted, toReversed, toSpliced, and with create modified copies of arrays without changing the original.

For instance, we write

const array = [3, 1, 4, 1, 5];
const sorted = array.toSorted();
console.log(sorted); // [1, 1, 3, 4, 5]
console.log(array); // [3, 1, 4, 1, 5]

const reversed = array.toReversed();
console.log(reversed); // [5, 1, 4, 1, 3]

Symbols as WeakMap Keys

Symbols can now be used as keys in WeakMaps and WeakSets.

For example:

const wm = new WeakMap();
const sym = Symbol("key");
wm.set(sym, "value");
console.log(wm.get(sym)); // 'value'

Hashbang Grammar

JavaScript now supports hashbangs (#!) for use in scripts, improving interoperability with Unix-like systems.

For example, we write:

#!/usr/bin/env node
console.log('Hello, world!');

Promise with Any

Promise.any returns the first fulfilled promise from a set of promises, or rejects if all of them reject.

For instance, we write

const p1 = Promise.reject("Error 1");
const p2 = Promise.resolve("Success");
const p3 = Promise.reject("Error 2");

Promise.any([p1, p2, p3])
  .then((value) => console.log(value)) // 'Success'
  .catch((error) => console.error(error));

WeakRef and FinalizationRegistry

WeakRef provides a way to hold weak references to objects, and FinalizationRegistry allows registering cleanup operations to be performed after an object is garbage collected.

Example:

let target = { name: "target" };
const weakRef = new WeakRef(target);

const registry = new FinalizationRegistry((heldValue) => {
  console.log(`Cleanup after ${heldValue}`);
});

registry.register(target, "target");

target = null; // `target` is now eligible for garbage collection

Temporal

The Temporal API offers a modern way to handle dates and times, providing more accurate and intuitive methods than the existing Date object.

Example:

const now = Temporal.Now.plainDateTimeISO();
console.log(now.toString()); // e.g., '2023-07-01T12:34:56'

const birthday = Temporal.PlainDate.from("2000-01-01");
const age = now.since(birthday);
console.log(`You are ${age.years} years old.`); // 'You are 23 years old.'

These updates in ES2023 bring more flexibility, modern functionality, and improved performance to JavaScript development.

Categories
JavaScript

What’s New in ES2024?

ECMAScript 2024 (ES15) introduces several significant features aimed at enhancing JavaScript’s functionality and developer experience.

Here are some of the key updates:

Pipe Operator (|>)

This operator enables more readable and maintainable code by allowing the output of one function to be used as the input for the next, streamlining data transformations.

For example:

const result = value |> firstFunction |> secondFunction;

This eliminates the need for deeply nested function calls, improving code clarity.

Records and Tuples

These immutable data structures ensure that their contents cannot be changed after creation, providing a robust way to manage immutable data in JavaScript.

Records are like objects, and tuples are like arrays but immutable. For instance:

const record = #{ name: "Alice", age: 30 };
const tuple = #["apple", "banana"];

This helps in maintaining predictable state management in applications

Array Grouping Methods

The Array.prototype.groupBy and Array.prototype.groupByToMap methods allow you to group array elements based on a callback function, simplifying data categorization.

For example:

const animals = [
  { name: "Lion", type: "Mammal" },
  { name: "Shark", type: "Fish" },
];
const grouped = animals.groupBy((animal) => animal.type);

This results in a more organized and manageable data structure.

Temporal API

This new API provides a modern approach to handling dates and times, addressing many shortcomings of the existing Date object.

It allows for more precise and flexible date-time operations, such as:

const now = Temporal.Now.plainDateTimeISO();
const birthday = Temporal.PlainDate.from("2000-01-01");
const age = now.since(birthday);

This is especially useful for internationalization and dealing with different time zones.

Top-Level Await

This feature allows the use of await at the top level of modules, simplifying asynchronous code by removing the need to wrap await calls in async functions.

For example:

const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);

This enhances code readability and reduces boilerplate code.

RegExp Match Indices

The d flag in regular expressions provides start and end positions of matched substrings, offering more detailed match information.

For example:

const regex = /(foo)/d;
const match = regex.exec("foo bar foo");
console.log(match.indices);

This is useful for more precise substring manipulation.

Enhanced Error Cause

This feature allows errors to include a cause property, improving error handling and debugging by linking related errors together.

For instance, we set the original cause to the error:

try {
 // some code
} catch (originalError) {
 throw new Error("Enhanced error", { cause: originalError });
}

This makes it easier to trace the root cause of errors in complex applications

These features collectively enhance JavaScript’s robustness, readability, and functionality, making it a more powerful and developer-friendly language.