לדלג לתוכן

2.5 מערכים הרצאה

מה זה מערך - array

מערך הוא רשימה מסודרת של ערכים. זה המקבילה של list בפייתון.

const fruits = ["apple", "banana", "cherry"];
const numbers = [1, 2, 3, 4, 5];
const mixed = [1, "hello", true, null, [1, 2]]; // can mix types, like Python
const empty = [];
# Python equivalent
# fruits = ["apple", "banana", "cherry"]
# numbers = [1, 2, 3, 4, 5]
# mixed = [1, "hello", True, None, [1, 2]]
# empty = []

יצירת מערכים

// literal syntax (recommended)
const colors = ["red", "green", "blue"];

// Array constructor (less common)
const arr1 = new Array(3);         // creates array with 3 empty slots
const arr2 = new Array(1, 2, 3);   // creates [1, 2, 3]

// Array.from (useful for converting things to arrays)
const chars = Array.from("hello"); // ["h", "e", "l", "l", "o"]
const range = Array.from({length: 5}, (_, i) => i); // [0, 1, 2, 3, 4]
  • כמעט תמיד משתמשים בסוגריים מרובעים [] ליצירת מערכים
  • Array.from("hello") דומה ל-list("hello") בפייתון
  • Array.from({length: 5}, (_, i) => i) יוצר מערך כמו list(range(5)) בפייתון

בדיקה אם משהו הוא מערך

console.log(Array.isArray([1, 2, 3])); // true
console.log(Array.isArray("hello"));   // false
console.log(Array.isArray({a: 1}));    // false
  • typeof [1,2,3] מחזיר "object" - לא עוזר!
  • משתמשים ב-Array.isArray() כדי לבדוק אם משהו הוא מערך
  • בפייתון: isinstance([1,2,3], list)

גישה לאיברים

לפי אינדקס

const fruits = ["apple", "banana", "cherry", "date"];

console.log(fruits[0]);  // "apple" (first element)
console.log(fruits[1]);  // "banana"
console.log(fruits[3]);  // "date" (last element)
console.log(fruits[10]); // undefined (no error, just undefined!)

בפייתון fruits[10] זורק IndexError. ב-JS מקבלים undefined - צריך להיזהר!

אינדקס שלילי עם at()

בפייתון אפשר לגשת לאיברים מהסוף עם אינדקס שלילי: fruits[-1]. ב-JS אינדקס שלילי לא עובד עם סוגריים מרובעים, אבל יש את המתודה at():

const fruits = ["apple", "banana", "cherry", "date"];

// negative index with brackets - doesn't work!
console.log(fruits[-1]); // undefined (not "date"!)

// .at() method - supports negative indices (like Python!)
console.log(fruits.at(0));  // "apple"
console.log(fruits.at(-1)); // "date" (last element)
console.log(fruits.at(-2)); // "cherry" (second to last)
# Python
# fruits[-1]   # "date"
# fruits[-2]   # "cherry"

אורך המערך - length

const fruits = ["apple", "banana", "cherry"];
console.log(fruits.length); // 3
  • length הוא property, לא פונקציה - בלי סוגריים!
  • בפייתון זה len(fruits) - פונקציה
// access last element
console.log(fruits[fruits.length - 1]); // "cherry"
// or
console.log(fruits.at(-1)); // "cherry" (cleaner)

שינוי ערכים

const fruits = ["apple", "banana", "cherry"];
fruits[1] = "blueberry"; // change second element
console.log(fruits); // ["apple", "blueberry", "cherry"]
  • אפשר לשנות איברים במערך גם אם הוא const
  • const מונע שינוי של ההפניה (reference), לא של התוכן
  • זה כמו בפייתון - fruits = ["new list"] לא עובד, אבל fruits[0] = "new" עובד

מתודות שמשנות את המערך - mutating methods

push ו-pop - הוספה והסרה מהסוף

const fruits = ["apple", "banana"];

// push - add to end (like Python's append)
fruits.push("cherry");
console.log(fruits); // ["apple", "banana", "cherry"]

fruits.push("date", "elderberry"); // can add multiple!
console.log(fruits); // ["apple", "banana", "cherry", "date", "elderberry"]

// pop - remove from end (like Python's pop)
const last = fruits.pop();
console.log(last);   // "elderberry"
console.log(fruits); // ["apple", "banana", "cherry", "date"]
# Python equivalent
# fruits.append("cherry")   # push
# last = fruits.pop()       # pop

unshift ו-shift - הוספה והסרה מההתחלה

const fruits = ["banana", "cherry"];

// unshift - add to beginning (no Python equivalent method)
fruits.unshift("apple");
console.log(fruits); // ["apple", "banana", "cherry"]

fruits.unshift("aaa", "bbb"); // can add multiple!
console.log(fruits); // ["aaa", "bbb", "apple", "banana", "cherry"]

// shift - remove from beginning (no Python equivalent method)
const first = fruits.shift();
console.log(first);  // "aaa"
console.log(fruits); // ["bbb", "apple", "banana", "cherry"]

בפייתון אין מקבילה ישירה. הדבר הקרוב:

# fruits.insert(0, "apple")  # unshift
# first = fruits.pop(0)       # shift

שימו לב: unshift ו-shift איטיים במערכים גדולים כי צריך להזיז את כל האיברים. push ו-pop מהירים.

splice - הסוויס-ארמי-נייף של מערכים

splice יכול להוסיף, להסיר, ולהחליף איברים בכל מקום במערך:

const fruits = ["apple", "banana", "cherry", "date", "elderberry"];

// remove 2 elements starting at index 1
const removed = fruits.splice(1, 2);
console.log(removed); // ["banana", "cherry"]
console.log(fruits);  // ["apple", "date", "elderberry"]

// insert elements at index 1 (remove 0 elements, add new ones)
fruits.splice(1, 0, "blueberry", "cantaloupe");
console.log(fruits); // ["apple", "blueberry", "cantaloupe", "date", "elderberry"]

// replace 1 element at index 2
fruits.splice(2, 1, "REPLACED");
console.log(fruits); // ["apple", "blueberry", "REPLACED", "date", "elderberry"]

התחביר: array.splice(startIndex, deleteCount, ...itemsToAdd)
- startIndex - מאיפה להתחיל
- deleteCount - כמה איברים למחוק
- ...itemsToAdd - אופציונלי, איברים להוסיף במקום


חיפוש במערך

indexOf ו-includes

const fruits = ["apple", "banana", "cherry", "banana"];

// indexOf - returns index of first occurrence (-1 if not found)
console.log(fruits.indexOf("banana"));  // 1
console.log(fruits.indexOf("grape"));   // -1

// includes - returns true/false
console.log(fruits.includes("cherry")); // true
console.log(fruits.includes("grape"));  // false

בפייתון:

# fruits.index("banana")  # 1 (throws ValueError if not found!)
# "cherry" in fruits       # True

הבדל חשוב: בפייתון index() זורק שגיאה אם לא נמצא, ב-JS indexOf() מחזיר -1.

find ו-findIndex

מחפשים לפי תנאי (callback):

const numbers = [1, 5, 12, 8, 3, 20, 7];

// find - returns the first element that matches
const firstBig = numbers.find(n => n > 10);
console.log(firstBig); // 12

// findIndex - returns the index of the first match
const firstBigIndex = numbers.findIndex(n => n > 10);
console.log(firstBigIndex); // 2

// if nothing found
const notFound = numbers.find(n => n > 100);
console.log(notFound); // undefined

const notFoundIndex = numbers.findIndex(n => n > 100);
console.log(notFoundIndex); // -1

דוגמה מעשית - חיפוש באובייקטים:

const users = [
    { name: "Alice", age: 25 },
    { name: "Bob", age: 30 },
    { name: "Charlie", age: 35 }
];

const user = users.find(u => u.name === "Bob");
console.log(user); // { name: "Bob", age: 30 }

const index = users.findIndex(u => u.age > 28);
console.log(index); // 1 (Bob is the first one over 28)

חיתוך - slice

slice מחזיר עותק של חלק מהמערך, בלי לשנות את המקור:

const fruits = ["apple", "banana", "cherry", "date", "elderberry"];

// slice(start, end) - from start up to (not including) end
console.log(fruits.slice(1, 3));  // ["banana", "cherry"]
console.log(fruits.slice(2));     // ["cherry", "date", "elderberry"]
console.log(fruits.slice(0, 2));  // ["apple", "banana"]
console.log(fruits.slice(-2));    // ["date", "elderberry"]
console.log(fruits.slice(1, -1)); // ["banana", "cherry", "date"]

// original array unchanged!
console.log(fruits); // ["apple", "banana", "cherry", "date", "elderberry"]

זה מאוד דומה ל-slicing בפייתון, אבל כ-method ולא בתחביר מיוחד:

# Python                    # JavaScript
# fruits[1:3]               # fruits.slice(1, 3)
# fruits[2:]                 # fruits.slice(2)
# fruits[:2]                 # fruits.slice(0, 2)
# fruits[-2:]                # fruits.slice(-2)

חשוב: slice לא משנה את המערך המקורי (immutable). splice כן משנה (mutable).


חיבור מערכים - concatenation

concat

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

const combined = arr1.concat(arr2);
console.log(combined); // [1, 2, 3, 4, 5, 6]
console.log(arr1);     // [1, 2, 3] (unchanged)

אופרטור spread - ...

דרך מודרנית ונפוצה יותר:

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];

const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]

// can add elements in between
const withMiddle = [...arr1, 99, ...arr2];
console.log(withMiddle); // [1, 2, 3, 99, 4, 5, 6]

בפייתון:

# arr1 + arr2              # [1, 2, 3, 4, 5, 6]
# [*arr1, *arr2]           # same thing with unpacking
# [*arr1, 99, *arr2]       # [1, 2, 3, 99, 4, 5, 6]

ה-spread operator (...) ב-JS דומה ל-unpacking operator (*) בפייתון.


המרות - join ו-split

join - מערך למחרוזת

const words = ["Hello", "World", "!"];
console.log(words.join(" "));  // "Hello World !"
console.log(words.join("-"));  // "Hello-World-!"
console.log(words.join(""));   // "HelloWorld!"
console.log(words.join(", ")); // "Hello, World, !"

בפייתון:

# " ".join(words)   # "Hello World !"
# "-".join(words)    # "Hello-World-!"

שימו לב לסדר ההפוך: בפייתון ה-separator קורא ל-join, ב-JS המערך קורא ל-join.

split - מחרוזת למערך

split היא מתודה של מחרוזת, לא של מערך:

const sentence = "Hello World from JavaScript";
const words = sentence.split(" ");
console.log(words); // ["Hello", "World", "from", "JavaScript"]

const csv = "Alice,25,Tel Aviv";
const parts = csv.split(",");
console.log(parts); // ["Alice", "25", "Tel Aviv"]

// split every character
const chars = "hello".split("");
console.log(chars); // ["h", "e", "l", "l", "o"]

בפייתון זה אותו דבר: "Hello World".split(" ").


מיון - sort

אזהרה חשובה: sort() ב-JS ממיין כמחרוזות כברירת מחדל!

const fruits = ["cherry", "apple", "banana"];
fruits.sort();
console.log(fruits); // ["apple", "banana", "cherry"] - correct!

// BUT with numbers:
const numbers = [10, 5, 100, 1, 25];
numbers.sort();
console.log(numbers); // [1, 10, 100, 25, 5] - WRONG! sorted as strings!
  • sort() ממיר הכל למחרוזות ומשווה לפי סדר אלפביתי
  • לכן 100 בא לפני 25 - כי "1" בא לפני "2" בסדר אלפביתי
  • זו הטעות הכי נפוצה ב-JS עם מערכים!

כדי למיין מספרים נכון, צריך פונקציית השוואה:

const numbers = [10, 5, 100, 1, 25];

// ascending order (small to large)
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 5, 10, 25, 100] - correct!

// descending order (large to small)
numbers.sort((a, b) => b - a);
console.log(numbers); // [100, 25, 10, 5, 1]

הפונקציה (a, b) => a - b מחזירה:
- מספר שלילי אם a צריך לבוא לפני b
- 0 אם הם שווים
- מספר חיובי אם b צריך לבוא לפני a

בפייתון sort() עובד נכון על מספרים כברירת מחדל:

# numbers = [10, 5, 100, 1, 25]
# numbers.sort()  # [1, 5, 10, 25, 100] - works correctly!

דוגמה - מיון אובייקטים:

const users = [
    { name: "Charlie", age: 35 },
    { name: "Alice", age: 25 },
    { name: "Bob", age: 30 }
];

// sort by age
users.sort((a, b) => a.age - b.age);
// [{ name: "Alice", age: 25 }, { name: "Bob", age: 30 }, { name: "Charlie", age: 35 }]

// sort by name
users.sort((a, b) => a.name.localeCompare(b.name));
// [{ name: "Alice"... }, { name: "Bob"... }, { name: "Charlie"... }]

שימו לב: sort() משנה את המערך המקורי!


היפוך - reverse

const numbers = [1, 2, 3, 4, 5];
numbers.reverse();
console.log(numbers); // [5, 4, 3, 2, 1]
  • reverse() משנה את המערך המקורי
  • בפייתון: numbers.reverse() או numbers[::-1] (שיוצר עותק)

אם רוצים לא לשנות את המקור:

const original = [1, 2, 3, 4, 5];
const reversed = [...original].reverse();
console.log(original); // [1, 2, 3, 4, 5] (unchanged)
console.log(reversed); // [5, 4, 3, 2, 1]

העתקת מערכים

העתקה שטחית - shallow copy

const original = [1, 2, 3];

// spread operator (most common)
const copy1 = [...original];

// slice
const copy2 = original.slice();

// Array.from
const copy3 = Array.from(original);

copy1.push(4);
console.log(original); // [1, 2, 3] (unchanged)
console.log(copy1);    // [1, 2, 3, 4]

אבל - העתקה שטחית לא מעתיקה אובייקטים מקוננים:

const nested = [[1, 2], [3, 4]];
const shallowCopy = [...nested];

shallowCopy[0].push(99);
console.log(nested);      // [[1, 2, 99], [3, 4]] - CHANGED!
console.log(shallowCopy); // [[1, 2, 99], [3, 4]]
  • ההעתקה השטחית מעתיקה את ההפניות למערכים הפנימיים, לא את המערכים עצמם
  • אותה בעיה קיימת בפייתון עם list.copy() או list[:]

העתקה עמוקה - deep copy

const nested = [[1, 2], [3, 4]];
const deepCopy = structuredClone(nested);

deepCopy[0].push(99);
console.log(nested);   // [[1, 2], [3, 4]] (unchanged!)
console.log(deepCopy); // [[1, 2, 99], [3, 4]]
  • structuredClone יוצר העתקה עמוקה - כולל כל המערכים והאובייקטים המקוננים
  • זה חדש יחסית (2022) אבל נתמך בכל הדפדפנים המודרניים
  • בפייתון: import copy; deep = copy.deepcopy(nested)

שיטוח מערכים - flat ו-flatMap

flat

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

console.log(nested.flat());    // [1, 2, 3, 4, [5, 6]] (one level)
console.log(nested.flat(2));   // [1, 2, 3, 4, 5, 6] (two levels)
console.log(nested.flat(Infinity)); // [1, 2, 3, 4, 5, 6] (all levels)
  • flat() משטח מערכים מקוננים
  • כברירת מחדל משטח רמה אחת
  • אפשר לציין עומק, או Infinity לשיטוח מלא

flatMap

משלב map ו-flat (נלמד על map בשיעור הבא):

const sentences = ["Hello World", "Good Morning"];
const words = sentences.flatMap(s => s.split(" "));
console.log(words); // ["Hello", "World", "Good", "Morning"]

מערכים מקוננים - nested arrays

// matrix (2D array)
const matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

console.log(matrix[0]);    // [1, 2, 3] (first row)
console.log(matrix[1][2]); // 6 (second row, third column)
console.log(matrix[2][0]); // 7 (third row, first column)

// iterating over a matrix
for (const row of matrix) {
    for (const cell of row) {
        console.log(cell);
    }
}

בפייתון זה אותו דבר:

# matrix[0]     # [1, 2, 3]
# matrix[1][2]  # 6


טבלת השוואה - פייתון מול JS

פעולה Python JavaScript
יצירה [1, 2, 3] [1, 2, 3]
אורך len(arr) arr.length
הוספה לסוף arr.append(x) arr.push(x)
הסרה מהסוף arr.pop() arr.pop()
הוספה להתחלה arr.insert(0, x) arr.unshift(x)
הסרה מההתחלה arr.pop(0) arr.shift()
חיתוך arr[1:3] arr.slice(1, 3)
חיפוש x in arr arr.includes(x)
אינדקס arr.index(x) arr.indexOf(x)
חיבור arr1 + arr2 [...arr1, ...arr2]
מיון arr.sort() arr.sort((a,b) => a-b)
היפוך arr.reverse() arr.reverse()
מחרוזת ",".join(arr) arr.join(",")
פיצול s.split(",") s.split(",")
אחרון arr[-1] arr.at(-1)
בדיקת סוג isinstance(x, list) Array.isArray(x)
העתקה שטחית arr.copy() [...arr]
העתקה עמוקה copy.deepcopy(arr) structuredClone(arr)

סיכום

  • מערכים ב-JS הם כמו lists בפייתון - מסודרים, גמישים, ומכילים כל טיפוס
  • push/pop לסוף, unshift/shift להתחלה, splice לכל מקום
  • slice מחזיר עותק (לא משנה מקור), splice משנה את המקור
  • אזהרה: sort() ממיין כמחרוזות! צריך (a,b) => a-b למספרים
  • find/findIndex מחפשים לפי תנאי (callback)
  • at(-1) לגישה מהסוף - כמו אינדקס שלילי בפייתון
  • spread [...arr] ליצירת עותקים ולחיבור מערכים
  • structuredClone להעתקה עמוקה
  • בשיעור הבא נלמד על המתודות המתקדמות: map, filter, reduce ועוד