02-Array Concept & Coding Question (JS)

02-Array Concept & Coding Question (JS)

Array: Array is a collection of heterogeneous data types separated by comma in square bracket.
An array in JavaScript is a mutable, non-primitive data type that serves as a reference to a collection of elements. It allows for the storage of heterogeneous data and supports dynamic resizing and modification of its contents.

In JavaScript:

  • Mutable: These data types can be modified after creation. Changes made to mutable objects directly affect the original object.

    • Objects (including arrays, functions, and plain objects created with {})

    • Arrays

    • Functions

let array = [1, 2, 3];

// Modifying array elements
array[0] = 10;
array.push(4);

console.log(array); // Output: [10, 2, 3, 4]
  • Immutable: Immutable data types cannot be changed after creation. Operations on immutable data types return new values instead of modifying the original. Once created, their values remain fixed.

    • Primitive data types (such as strings, numbers, booleans) -> they are capable of making copy of their own.

    • Special types like undefined and null

let str = "hello";
str.toUpperCase(); // Returns a new string "HELLO", but doesn't change the original 'str' value
console.log(str); // Outputs: "hello"

Array methods and properties:

Read-Only Methods

These methods do not modify the original array and instead return a new array or a value based on the operations performed.

MethodDescriptionExample
concat()Combines two or more arrays, returning a new array without modifying the original arrays.const newArray = array1.concat(array2);
includes()Determines whether an array includes a certain element, returning true or false as appropriate.const isIncluded = array.includes(5);
indexOf()Returns the first index at which a given element can be found in the array, or -1 if it is not present.const index = array.indexOf(5);
join()Joins all elements of an array into a string, optionally separated by a specified separator string.const joinedString = array.join(", ");
lastIndexOf()Returns the last index at which a given element can be found in the array, or -1 if it is not present.const lastIndex = array.lastIndexOf(5);
slice()Returns a shallow copy of a portion of an array into a new array object selected from begin to end (end not included).const newArray = array.slice(1, 3);
toString()Returns a string representing the specified array and its elements.const arrayString = array.toString();
valueOf()Returns the primitive value of the specified object.const primitiveValue = array.valueOf();

Mutator Methods

These methods modify the original array.

MethodDescriptionExample
pop()Removes the last element from an array and returns that element.const lastElement = array.pop();
push()Adds one or more elements to the end of an array and returns the new length of the array.const newLength = array.push(6, 7);
reverse()Reverses the order of the elements in an array, modifying the array, and returning a reference to the array.array.reverse();
shift()Removes the first element from an array and returns that removed element.const firstElement = array.shift();
sort()Sorts the elements of an array in place and returns the sorted array.array.sort();
splice()Changes the contents of an array by removing or replacing existing elements and/or adding new elements in place. Returns an array containing the deleted elements, or an empty array if none.const removedElements = array.splice(2, 2, 'a', 'b');
unshift()Adds one or more elements to the beginning of an array and returns the new length of the array.const newLength = array.unshift(-2, -1);
fill()Fills all the elements of an array from a start index to an end index with a static value and modifies the original array.let array = [1, 2, 3, 4, 5];
array.fill(0);
// You can also specify the start and end index to fill array.fill(9, 1, 3);
// Filling with value 9 from index 1 to 3 (exclusive)

Iteration Methods

These methods iterate over the elements of the array, performing a specified operation on each element.

MethodDescriptionExample
forEach()Executes a provided function once for each array element.array.forEach(function(element) { console.log(element); });
every()Tests whether all elements in the array pass the test implemented by the provided function.const allPass = array.every(function(element) {
return element > 5;
});
some()Tests whether at least one element in the array passes the test implemented by the provided function.const hasSome = array.some(function(element) {
return element > 5;
});
filter()Creates a new array with all elements that pass the test implemented by the provided function.const filteredArray = array.filter(function(element) {
return element > 5;
});
map()Creates a new array populated with the results of calling a provided function on every element in the calling array.const newArray =array.map(function(element) {
return element * 2;
});
reduce()Executes a reducer function on each element of the array, resulting in a single output value.const sum = array.reduce(function(acc, currVal) {
return acc + currentValue;
}, 0);
reduceRight()Executes a reducer function (from right to left) on each element of the array, resulting in a single output value.const sum = array.reduceRight(function(acc, currVal) {
return accumulator + currVal;
}, 0);
find()Returns the first element in the array that satisfies the provided testing function.const foundElement = array.find(function(element) { return element > 5; });
findIndex()Returns the index of the first element in the array that satisfies the provided testing function.const foundIndex = array.findIndex(function(element) { return element > 5; });

The length property is not included in the table because it's a property rather than a method, but it's worth mentioning as it provides the number of elements in the array.

How do you create an empty array in JavaScript ?

const arr1 = []; console.log(arr1); console.log(arr1.length);

const arr2 = new Array(); console.log(arr2); console.log(arr2.length);

let a = 90; console.log(a);

Access the first and last elements ?

const arr = [12, 24, 36, 48, 60]; 
const firstElement = arr[0]; 
const lastElement = arr[arr.length - 1];

console.log(firstElement, lastElement, arr.length);

ARRAY MANIPULATION:

1. Remove Last Element

let arr = [1, 2, 3, 4, 5];

// Removing the last element from the array
const removedElement = arr.pop();

console.log("Removed element:", removedElement); // Output: 5
console.log("Array after removing last element:", arr); // Output: [1, 2, 3, 4]

2. Add elements to end

const arr = [1, 2, 3];
// Using push() to add elements to the end of the array
const newLengthAfterPush = arr.push(4, 5, 6);
console.log(newLengthAfterPush);    // Output: 6 (length after push)

3. Add Element to Start:

const arr = [1, 2, 3];
// Using unshift() to add elements to the beginning of the array
const newLengthAfterUnshift = arr.unshift(-3, -2, -1);4. Remove First Element:
console.log(newLengthAfterUnshift); // Output: 9 (length after unshift)

4. Remove First Element:

let arr = [1, 2, 3, 4, 5];

// Removing the first element from the array
const removedElement = arr.shift();

console.log("Removed element:", removedElement); // Output: 1
console.log("Array after removing first element:", arr); // Output: [2, 3, 4, 5]

Array Iteration

1. Using a for loop:

const arr = [1, 2, 3, 4, 5];

// Using a for loop
for (let i = 0; i < arr.length; i++) {
    console.log(arr[i]); // Output: 1, 2, 3, 4, 5
}

2.Using the forEach() method:

  • Iterates over each element in the array and executes a provided callback function.

  • Returns undefined.

  • Does not modify the original array.

  • Useful for side effects or actions on array elements.

// Using forEach method
arr.forEach(function(element) {
    console.log(element); // Output: 1, 2, 3, 4, 5
    console.log(typeof elem); // 'number', 'number', 'number', ...    
    console.log(i);     // 0, 1, 2, 3, 4, 5
});
  • The forEach() method in JavaScript does not return anything (i.e., it returns undefined)
const result = arr.forEach(function(element) {
    return element * 2;
});
console.log(result); // Output: undefined

3.Using map() method:

  1. Iterates: Loops through each element of the array.

  2. Creates: Generates a new array.

  3. Returns: Provides a result as a new array.

  4. Preserves: Leaves the original array unchanged.

  5. Transforms: Allows for element-wise transformation using a provided function.

const arr = [1, 2, 3, 4, 5];

const doubledArray = arr.map(function(element) {
    return element * 2;
});

console.log(doubledArray); // Output: [2, 4, 6, 8, 10]

4. for...of Loop :

  • Value Iteration: Iterates over values directly rather than indices, enhancing readability.
const arr = [1, 2, 3, 4, 5];

for (let element of arr) {
    console.log(element); // Output: 1, 2, 3, 4, 5 (Prints each element of the array)
}

5.1 for...in method:

In JavaScript, a for...in loop is used to iterate over the enumerable properties of an object. It iterates through all enumerable properties of an object, including properties inherited from its prototype chain. Here's the syntax:

for (variable in object) {
  // code block to be executed
}
  • variable: A variable that represents the property name for each iteration.

  • object: The object whose enumerable properties are being iterated over.

Here's an example to demonstrate its usage:

const person = {
  name: 'John',
  age: 30,
  gender: 'male'
};

for (let key in person) {
  console.log(`${key}: ${person[key]}`);
}

In this example, the for...in loop iterates over the person object and prints each property name and its corresponding value.

5.2 for...in method: (⚠️ it should be used with caution, especially when dealing with arrays)

While for...in loops can be used with arrays in JavaScript, it's generally not recommended due to:

  1. Unpredictable Order: They don't guarantee the order of iteration.

  2. Prototype Properties: They iterate over all enumerable properties, including those inherited from prototypes.

  3. Non-Numeric Properties: They may also iterate over non-numeric properties of the array.

For iterating over arrays, it's better to

let arr = [10, 20, 30];
arr.foo = 'bar';

for (let key in arr) {
  console.log(key); // prints 0, 1, 2, foo
}

for (let val of arr) {
  console.log(val); // prints 10, 20, 30
}

Array Element Check and Index

1. Check if Element Exists:

const arr = [6, 12, 18, 24, 30, 36, 42, 48, "Hare", "Krishna"];

const findElement = (arr, target) => {
    for (let x of arr) {
        if (x === target) {
            return true;
        }
    }
    return false;
}

console.log(findElement(arr, 42));     // true
console.log(findElement(arr, "hare")); // false
console.log(findElement(arr, "Krishna")); // true
console.log(findElement(arr, "Kris"));    // false

console.log(arr.includes("Kris"));    // false
console.log(arr.includes("Krishna")); // true

2.Find Index of an Element:

arr; // [6, 12, 18, 24, 30, 36, 42, 48, "Hare", "Krishna"]

// user defined Function to find the index of an element in the array
function indexOfElem(arr, target) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === target) {
            console.log(i); // 4, 2, -1
            return i;
        }
    }
    return -1;
}
console.log(indexOfElem(arr, 30)); //  4
console.log(indexOfElem(arr, 18)); //  2
console.log(indexOfElem(arr, 15)); // -1
console.log(arr.indexOf("Krishna")); // 9

🎯 How to delete, add & update elements from a specific index?

1. slice()

Features:

  • Extracts a portion of an array without modifying the original array.

  • Returns a new array containing the extracted elements.

  • The end index is exclusive, meaning the element at the end index is not included in the extracted slice.

  • If no end index is provided, it slices until the end of the array.

  • It accepts negative indices, which count from the end of the array.

let array = [1, 2, 3, 4, 5];

// Extract elements from index 1 to index 3 (exclusive)
let slicedArray = array.slice(1, 3);
console.log(slicedArray); // Output: [2, 3]

// Extract elements from index 2 to the end
let slicedArray2 = array.slice(2);
console.log(slicedArray2); // Output: [3, 4, 5]

// Extract last two elements using negative indices
let slicedArray3 = array.slice(-2);
console.log(slicedArray3); // Output: [4, 5]

Create a copy of an array using the slice() method:

const originalArray = [1, 2, 3, 4, 5];

// Creating a copy of the original array using slice() and spread operator
const copiedArray = originalArray.slice();
// const copiedArray = [...originalArray];

console.log("Original Array:", originalArray);
console.log("Copied Array:", copiedArray);
Featureslice()splice()
PurposeExtracts a portion of an arrayModifies an array by removing, replacing, or adding elements
Original arrayDoes not modifyModifies
Return valueNew array containing extracted elementsArray of removed elements (if any)
Syntaxarray.slice(start, end)array.splice(start, deleteCount, items)
Parametersstart: Index to start extraction <br> end: Index to end extraction (optional)start: Index to start modification <br> deleteCount: Number of elements to remove <br> items: Elements to add (optional)
Side effectsNoneModifies the original array

2.splice()

Features:

  • Modifies an array by removing, replacing, or adding elements.

  • Returns an array of removed elements (if any).

  • It directly modifies the original array.

  • You can specify the starting index, the number of elements to remove, and optionally add new elements.

let array = [1, 2, 3, 4, 5];

// Remove 2 elements starting from index 1
let removedElements = array.splice(1, 2);
console.log(array); // Output: [1, 4, 5]
console.log(removedElements); // Output: [2, 3]

// Replace 1 element at index 1 with 'a' and 'b'
array.splice(1, 1, 'a', 'b');
console.log(array); // Output: [1, 'a', 'b', 4, 5]

// Add elements at index 2 without removing any
array.splice(2, 0, 'x', 'y');
console.log(array); // Output: [1, 'a', 'x', 'y', 'b', 4, 5]

🎯 Shallow Copy of Array

  • Creates a new array and copies all elements from the original array, but nested arrays are copied by reference.
FeatureShallow CopyDeep Copy
CopiesCopies references to nested objectsCopies nested objects completely
Impact of ChangesReflects changes in original structureOriginal structure remains unaffected
PerformanceFaster, less memory-intensiveSlower, more memory-intensive
DependencyChanges affect original, vice versaCopied structure is isolated
let originalArray = [ 6, 7, 8, 9, 48, 'Hare', 'Krishna' ];

let shallowCopy = originalArray ;
shallowCopy;    // [ 6, 7, 8, 9, 48, 'Hare', 'Krishna' ]
shallowCopy.pop(); // 
shallowCopy; // [ 6, 7, 8, 9, 48, 'Hare' ] 
originalArray ;  // [ 6, 7, 8, 9, 48, 'Hare' ]

🎯 Deep Copy of Array:

  • Produces a new array and recursively copies all elements, including nested arrays, resulting in entirely independent arrays.
arr; // [ 6, 7, 8, 9, 48, 'Hare' ]

arrD = [...arr];
arrD; // [ 6, 7, 8, 9, 48, 'Hare' ]
arrD.pop();
arrD; // [ 6, 7, 8, 9, 48 ] 
arr;  // [ 6, 7, 8, 9, 48, 'Hare' ]

🎯Concatenate two array in JS ?

a. Using concat() method:

const array1 = [1, 2, 3];
const array2 = [4, 5, 6];

const concatenatedArray = array1.concat(array2);

console.log(concatenatedArray); // Output: [1, 2, 3, 4, 5, 6]

b. Using spread syntax (...):

const array1 = [1, 2, 3];
const array2 = [4, 5, 6];

const concatenatedArray = [...array1, ...array2];

console.log(concatenatedArray); // Output: [1, 2, 3, 4, 5, 6]

Equality Check for Arrays

Approach 1: Using a loop to compare each element

const isArrayEqual = (arr1, arr2) => {
    // Check if arrays have different lengths
    if (arr1.length != arr2.length) {
        return false; // If lengths are different, arrays are not equal
    }

    // Iterate through each element of the arrays
    for (let i = 0; i < arr1.length; i++) {
        // If corresponding elements are not equal, arrays are not equal
        if (arr1[i] !== arr2[i]) {
            return false;
        }
    }

    // If all elements are equal, arrays are equal
    return true;
}

Approach 2: using every() method

function arraysAreEqual(arr1, arr2) {
    // Check if arrays are of equal length
    if (arr1.length !== arr2.length) {
        return false;
    }

    // Check each element for equality
    return arr1.every((value, index) => value === arr2[index]);
}

// Example usage
const array1 = [1, 2, 3];
const array2 = [1, 2, 3];
const array3 = [1, 2, 4];

console.log(arraysAreEqual(array1, array2)); // Output: true
console.log(arraysAreEqual(array1, array3)); // Output: false

Approach 3: Using Array.prototype.every() and one-liner solution

const isArrayEqual2 = (arr1, arr2) => {
    // one Line Solution
    return arr1.length === arr2.length && arr.every((elem, i) => arr1[i] === arr2[i]);
}
// Test data
let arr1 = [5, 18, 15, 4, 2, 41, 37];
let arr2 = [5, 18, 15, 4, 2, 41, 37];
result = isArrayEqual(arr1, arr2);
console.log(result);    // true

result = isArrayEqual2(arr1, arr2);
console.log(result);    // true

Question : Sort an array

  • In both cases, slice() is used to create a copy of the original array to avoid mutating the original array.

  • Then, sort() is called with a comparison function.

In ascending order

  • For ascending order, the comparison function subtracts b from a.
const arr = [3, 1, 5, 2, 4];

// Ascending order
const ascendingOrder = arr.slice().sort((a, b) => a - b);
console.log("Ascending Order:", ascendingOrder);

In Descending order

  • For descending order, it subtracts a from b.
const arr = [3, 1, 5, 2, 4];

// Descending order
const descendingOrder = arr.slice().sort((a, b) => b - a);
console.log("Descending Order:", descendingOrder);

Question 5: reverse an array?

arr5 = [5, 15, 10, 45, 35];
arr5.reverse(); // reverses the order of elements in the array in place
arr5;    // [ 35, 45, 10, 15, 5 ]

🎯 Map, Filter & Reduce

1.map:

  • map is used to iterate over an array and transform each element in the array based on a given function.

  • It returns a new array containing the results of applying the provided function to each element of the original array without modifying the original array.

// Example: Doubling each element in an array using map
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(num => num * 2);
console.log(doubledNumbers); // Output: [2, 4, 6, 8, 10]

2.filter:

  • filter is used to iterate over an array and select elements that satisfy a given condition.

  • It returns a new array containing only the elements of the original array for which the provided function returns true.

// Example: Filtering even numbers from an array using filter
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // Output: [2, 4]

3.Reduce:

  • reduce is used to iterate over an array and accumulate a single result by applying a given function to each element of the array.

  • It takes an accumulator and each element of the array, and returns a single value as a result.

// Example: Summing up all numbers in an array using reduce
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
console.log(sum); // Output: 15 (1 + 2 + 3 + 4 + 5)
let arr = [1, 2, 3, 4, 5];
let sumOfArr = arr.reduce((acc, elem) => {
    console.log(elem);  //   2, 3, 4, 5
    console.log(acc);  // 1, 3, 6, 10
    return acc += elem;
});
sumOfArr; // 15

🎯 Filter v/s find

Featurefilter()find()
PurposeSelects elements based on a conditionFinds the first element based on a condition
ReturnReturns an array containing all matching elementsReturns the first matching element
IterationContinues iteration over all elementsStops iteration once the first match is found
Use CaseWhen multiple matches are expectedWhen only the first match is needed
Exampleconst evenNumbers = numbers.filter(num => num % 2 === 0);const firstEven = numbers.find(num => num % 2 === 0);

find() method

  • Finds the first element in an array that satisfies a condition.

  • Invoked on an array with a callback function defining the condition.

  • Returns the first matching element, undefined if no match.

  • Stops iteration after finding the first match.

  • Does not modify the original array.

  • Useful for searching specific elements efficiently.

// Example 1: Finding the first even number in an array
const numbers = [1, 3, 5, 6, 7, 9];
const firstEven = numbers.find(num => num % 2 === 0);
console.log(firstEven); // Output: 6

// Example 2: Finding the first element greater than 10 in an array
const values = [8, 12, 6, 15, 3];
const greaterThan10 = values.find(value => value > 10);
console.log(greaterThan10); // Output: 12

// Example 3: Finding the first element that starts with 'a' in an array of strings
const fruits = ['apple', 'banana', 'orange', 'kiwi'];
const startsWithA = fruits.find(fruit => fruit.startsWith('a'));
console.log(startsWithA); // Output: 'apple'

// Example 4: Finding an object by a property value
const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' }
];
const user = users.find(user => user.id === 2);
console.log(user); // Output: { id: 2, name: 'Bob' }

🎯 flat

The flat() method in JavaScript is used to flatten a nested array, collapsing all nested arrays into one flat array. It returns a new array without modifying the original one.

// Nested array
const nestedArray = [1, 2, [3, 4], [5, [6, 7]]];

// Using flat() to flatten the array
const flatArray = nestedArray.flat();

console.log(flatArray); // Output: [1, 2, 3, 4, 5, [6, 7]]

// You can also specify the depth to which the array should be flattened
const deeplyNestedArray = [1, [2, [3, [4, [5]]]]];
const flatDeepArray = deeplyNestedArray.flat(3);

console.log(flatDeepArray); // Output: [1, 2, 3, 4, [5]]