תרגיל תכנות - איתור המספר הראשון הייחודי
לא מזמן נתקלתי באתגר הזה שנראה לי מספיק פשוט בשביל לפתור בכמה שפות - יש לנו רשימה של מספרים והמשימה היא למצוא את המספר הראשון שמופיע רק פעם אחת ברשימה ולהדפיס את האינדקס שלו.
בכל שפה שיש בה 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