• בלוג
  • תרגיל תכנות - איתור המספר הראשון הייחודי

תרגיל תכנות - איתור המספר הראשון הייחודי

01/09/2022

לא מזמן נתקלתי באתגר הזה שנראה לי מספיק פשוט בשביל לפתור בכמה שפות - יש לנו רשימה של מספרים והמשימה היא למצוא את המספר הראשון שמופיע רק פעם אחת ברשימה ולהדפיס את האינדקס שלו.

בכל שפה שיש בה Hash הפיתרון יראה דומה ופשוט. אפשר לרוץ על הרשימה, לספור כמה פעמים מופיע כל מספר שם ואז לרוץ שוב ולחפש את המספר הראשון שמופיע רק פעם אחת, לדוגמה ברובי:

# 33 is the first unique number
items = [10, 22, 33, 10, 12, 22, 9, 5, 1]

counts = items.each_with_object(Hash.new(0)) do |item, acc|
  acc[item] += 1
end

first_unique_index = items.find_index {|item| counts[item] == 1 }

if first_unique_index
  puts "Unique Index = #{first_unique_index}; Item = #{items[first_unique_index]}"
end

פייתון:

from collections import Counter

# 33 is the first unique number
items = [10, 22, 33, 10, 12, 22, 9, 5, 1]

counts = Counter(items)

index, item = next(
        filter(lambda x: counts[x[1]] == 1, enumerate(items)),
        None)

print(f"First unique index is {index}; item is {item}")

ג'אווהסקריפט:

// 33 is the first unique number
const items = [10, 22, 33, 10, 12, 22, 9, 5, 1]
const counts = {};
items.forEach(i => counts[i] ? counts[i]++ : counts[i] = 1);

const index = items.findIndex(i => counts[i] === 1);

if (index) {
  console.log(`Found at index ${index} value ${items[index]}`);
}

קצת יותר מעניין לפתור את זה בסביבה שאין בה Hash או אפילו משתנים, ובשביל המשחק לקחתי את שורת הפקודה של יוניקס. מסתבר שגם כאן המשחק לא מסובך בכלל:

echo 10 22 33 10 12 22 9 5 1 | tr ' ' '\n' | cat -n | sed 's/^ *//' | sort -k 2 -n | uniq -f 1 -c | sed 's/^ *//' | grep -w '^1' | sort -k 2 -n | cut -c 3- | head -1

בגדול זה טריק דומה, רק עקום - אנחנו מוסיפים אינדקסים לכל השורות עם cat -n, אחרי זה ממיינים לפי הערך כדי שנוכל להפעיל uniq -c שסופר כמה פעמים מופיע כל דבר, ואז עם grep נשארים רק עם אלה שמופיעים פעם אחת, ממיינים חזרה לפי האינדקסים ולוקחים את הראשון.

מוזמנים להוסיף בתגובות פיתרונות שלכם בשפות יצירתיות יותר או פחות.

הרעיון לתרגיל הגיע ממוחמד מהגיליון האחרון של Perl Weekly Challenge בקישור: https://theweeklychallenge.org/blog/perl-weekly-challenge-180/#TASK1