Практическая задача: Реализуйте функцию на Go, которая парсит большой текстовый файл (содержащий миллионы строк) с записями в формате: id,name,score

Читайте файл потоково и храните только 10 лучших записей. При равном 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.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее