← Назад к вопросам

Преобразование строки в nested объект

2.0 Middle🔥 101 комментариев
#Алгоритмы и структуры данных

Условие

Напишите функцию, которая преобразует строку с точками в nested объект:

function stringToNestedObject(str, value) {
  // Ваш код
}

console.log(stringToNestedObject("a.b.c", 42));
// { a: { b: { c: 42 } } }

console.log(stringToNestedObject("user.name.first", "John"));
// { user: { name: { first: "John" } } }

Что проверяется

  • Работа со строками (split)
  • Динамическое создание объектов
  • Рекурсия или reduce

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

Эта задача требует создания вложенной структуры объектов, где каждая точка в строке представляет уровень вложенности. Разберу несколько подходов.

Подход 1: С использованием reduce (элегантный)

function stringToNestedObject(str: string, value: any): Record<string, any> {
  // Разбиваем строку по точкам
  const keys = str.split(".");
  
  // Идём с конца и создаём объекты
  return keys.reduceRight((acc, key) => {
    return { [key]: acc };
  }, value);
}

// Примеры:
console.log(stringToNestedObject("a.b.c", 42));
// { a: { b: { c: 42 } } }

console.log(stringToNestedObject("user.name.first", "John"));
// { user: { name: { first: "John" } } }

Как работает:

  1. Разбиваем строку "a.b.c" на массив ["a", "b", "c"]
  2. reduceRight идёт справа налево (от конца)
  3. Стартуем с value (42)
  4. На каждом шаге оборачиваем текущий аккумулятор в новый объект с ключом
  5. Итераций: { c: 42 } → { b: { c: 42 } } → { a: { b: { c: 42 } } }

Временная сложность: O(n) где n = количество точек Пространственная сложность: O(n) для создания новых объектов

Подход 2: С использованием простого цикла (читаемо)

function stringToNestedObject(str: string, value: any): Record<string, any> {
  const keys = str.split(".");
  let result = value;
  
  // Идём с конца к началу
  for (let i = keys.length - 1; i >= 0; i--) {
    const key = keys[i];
    result = { [key]: result };
  }
  
  return result;
}

Преимущества:

  • Явная логика цикла легче понять
  • Легче отлаживать
  • Не требует понимания reduceRight

Подход 3: С использованием рекурсии

function stringToNestedObject(str: string, value: any): Record<string, any> {
  const keys = str.split(".");
  
  function buildNested(index: number): Record<string, any> {
    // Базовый случай: если дошли до конца
    if (index === keys.length) {
      return value;
    }
    
    // Рекурсивный случай
    const key = keys[index];
    return {
      [key]: buildNested(index + 1)
    };
  }
  
  return buildNested(0);
}

Особенности:

  • Классическая рекурсия
  • Прямой проход (слева направо), но через замыкание создаём объекты справа
  • Может привести к stackoverflow на очень глубоких путях

Подход 4: Прямой reduceRight с более понятным синтаксисом

function stringToNestedObject(str: string, value: any): Record<string, any> {
  const keys = str.split(".");
  
  return keys.reduceRight((acc, key) => {
    const result: Record<string, any> = {};
    result[key] = acc;
    return result;
  }, value);
}

Легче читать, чем { [key]: acc } синтаксис

Подход 5: Для глубокого доступа (бонус)

Если нужна функция для установки значения по пути (обратная операция для get):

function setNestedValue(obj: any, path: string, value: any): void {
  const keys = path.split(".");
  let current = obj;
  
  // Идём до предпоследнего ключа
  for (let i = 0; i < keys.length - 1; i++) {
    const key = keys[i];
    if (!(key in current) || typeof current[key] !== "object") {
      current[key] = {};
    }
    current = current[key];
  }
  
  // Устанавливаем значение на последний ключ
  current[keys[keys.length - 1]] = value;
}

// Использование
const obj = {};
setNestedValue(obj, "user.profile.name", "Alice");
console.log(obj); // { user: { profile: { name: "Alice" } } }

Тестирование

// Базовые тесты
const test1 = stringToNestedObject("a.b.c", 42);
console.log(test1.a.b.c === 42); // true

const test2 = stringToNestedObject("user.name.first", "John");
console.log(test2.user.name.first === "John"); // true

// Граничные случаи
console.log(stringToNestedObject("single", 99));
// { single: 99 }

console.log(stringToNestedObject("a.b", null));
// { a: { b: null } }

console.log(stringToNestedObject("x.y.z", { nested: true }));
// { x: { y: { z: { nested: true } } } }

// Глубокий объект
const deep = stringToNestedObject("a.b.c.d.e.f", "deep");
console.log(deep.a.b.c.d.e.f === "deep"); // true

Сравнение подходов

ПодходВремяЧитаемостьРекомендуется
reduceRightO(n)СредняяProduction, FP-стиль
Простой циклO(n)ОтличнаяИнтервью, новички
РекурсияO(n)СредняяПримеры, алгоритмы
Улучшенный reduceO(n)ХорошаяКогда reduce обязателен

Рекомендация для интервью

Начните с простого цикла справа налево — это наиболее понятно и показывает понимание алгоритма. Если интервьюер попросит функциональный подход, покажите reduceRight.

Ключевые моменты:

  • Разбиваем строку по точкам
  • Идём справа налево (от конца массива)
  • Оборачиваем значение в объекты уровень за уровнем
  • Временная сложность O(n) — один проход по массиву ключей
  • На каждом шаге создаём новый объект