Читайте файл потоково и храните только 10 лучших записей. При равном score сохраняйте более раннюю запись; весь файл загружать в память не требуется.
Практическая задача: Реализуйте функцию на Go, которая парсит большой текстовый файл (содержащий миллионы строк) с записями в формате: id,name,score
Читайте файл потоково и храните только 10 лучших записей. При равном score сохраняйте более раннюю запись; весь файл загружать в память не требуется.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Практическая задача: Реализуйте функцию на Go, которая парсит большой текстовый файл (содержащий миллионы строк) с записями в формате: id,name,score
Каждая строка представляет собой уникальную запись.
Функция должна эффективно находить 10 наивысших значений score и соответствующие им записи.
Особенности и требования:
Обрабатывать дубликаты значений score — при равных значениях приоритет должен отдаваться записям, которые встретились раньше (т.е. сохранять стабильность сортировки по порядку появления). Оптимизировать использование памяти — функция должна быть способна обрабатывать файл, не помещающийся целиком в память.
Ответ
Читайте файл потоково и храните только 10 лучших записей. При равном score сохраняйте более раннюю запись; весь файл загружать в память не требуется.
Для фиксированного k=10 достаточно поддерживать короткий упорядоченный список: O(n·10) времени и O(10) записей памяти, кроме текущей строки. Для произвольного большого k используют min-heap и O(n log k).
type Record struct {
ID, Name string
Score float64
}
func Top10(r io.Reader) ([]Record, error) {
reader := csv.NewReader(r)
reader.FieldsPerRecord = 3
best := make([]Record, 0, 11)
for {
row, err := reader.Read()
if err == io.EOF { break }
if err != nil { return nil, err }
score, err := strconv.ParseFloat(row[2], 64)
if err != nil || math.IsNaN(score) || math.IsInf(score, 0) {
return nil, fmt.Errorf("invalid score")
}
entry := Record{row[0], row[1], score}
pos := 0
for pos < len(best) && best[pos].Score >= score { pos++ }
if pos >= 10 { continue }
best = append(best, Record{})
copy(best[pos+1:], best[pos:len(best)-1])
best[pos] = entry
if len(best) > 10 { best = best[:10] }
}
return best, nil
}
Импорты: io, encoding/csv, strconv, math, fmt. Вход предполагается без заголовка; CSV-reader поддерживает кавычки. Равные оценки вставляются после прежних, поэтому стабильность сохранена. Для недоверенного файла отдельно ограничивают размер одной записи; при необходимости точного десятичного сравнения выбирают иной тип score.