hexlet-frontend
October 1, 2020

7. Агрегация 2

Научиться получать составной (массив) результат обхода дерева

Попрактикуемся ещё с одним вариантом агрегации данных на файловых системах. Напишем функцию, которая принимает на вход директорию и возвращает список директорий первого уровня вложенности и количество файлов внутри каждой из них, включая все поддиректории

const tree = mkdir('/', [
  mkdir('etc', [
    mkdir('apache'),
    mkdir('nginx', [
      mkfile('nginx.conf'),
    ]),
  ]),
  mkdir('consul', [
    mkfile('config.json'),
    mkfile('file.tmp'),
    mkdir('data'),
  ]),
  mkfile('hosts'),
  mkfile('resolve'),
]);

console.log(getSubdirectoriesInfo(tree));
// => [['etc', 1], ['consul', 2]]

Внутри себя эта задача распадается на две:

  • Подсчёт количества файлов внутри директории
  • Вызов функции подсчёта файлов на каждой из поддиректорий

Начнём с подсчёта количества файлов. Это классическая задача на агрегацию:

const getFilesCount = (node) => {
  if (isFile(node)) {
    return 1;
  }

  const children = getChildren(node);
  const descendantCounts = children.map(getFilesCount);
  return _.sum(descendantCounts);
};

Следующий шаг заключается в том, чтобы извлечь всех детей из исходного узла и к каждому из них применить подсчёт:

const getSubdirectoriesInfo = (tree) => {
  const children = getChildren(tree);
  const result = children
    // Нас интересуют только директории
    .filter(isDirectory)
    // Запускаем подсчёт для каждой директории
    .map((child) => [getName(child), getFilesCount(child)]);

  return result;
};

То есть мы обратились к детям напрямую сначала отфильтровав их, а затем выполнили отображение на необходимый массив, содержащий для каждой директории имя и количество файлов в нем.

Упражнение

Во многих операционных системах (Linux, MacOS) существует утилита du. Она умеет подсчитывать занимаемое место указанными файлами и директориями. Например, так:

 tmp$ du -sh *
  0B    com.docker.vmnetd.socket
 10M    credo
4.0K    debug.mjs
  0B    filesystemui.socket
4.0K    index.php
 37M    node_modules
 88K    package-lock.json
 22M    taxdome

Перед тем, как делать упражнение, обязательно попробуйте поиграйте с этой утилитой в терминале, посмотрите её опции через man du. Экспериментировать нужно в локально установленной операционной системе.

du.js

Реализуйте и экспортируйте по умолчанию функцию, которая принимает на вход директорию, а возвращает список узлов вложенных, (директорий и файлов) в указанную директорию на один уровень, и место которое, они занимают. Размер файла задается в метаданных. Размер директории складывается из сумм всех размеров файлов, находящихся внутри во всех поддиректориях. Сами директории размера не имеют.

Пример

import { mkdir, mkfile } from '@hexlet/immutable-fs-trees';
import du from '../du.js';

const tree = mkdir('/', [
  mkdir('etc', [
    mkdir('apache'),
    mkdir('nginx', [
      mkfile('nginx.conf', { size: 800 }),
    ]),
    mkdir('consul', [
      mkfile('config.json', { size: 1200 }),
      mkfile('data', { size: 8200 }),
      mkfile('raft', { size: 80 }),
    ]),
  ]),
  mkfile('hosts', { size: 3500 }),
  mkfile('resolve', { size: 1000 }),
]);

du(tree);
// [
//   ['etc', 10280],
//   ['hosts', 3500],
//   ['resolve', 1000],
// ]

Примечания

  • Обратите внимание на структуру результирующего массива. Каждый элемент — массив с двумя значениями: именем директории и размером файлов внутри.
  • Результат отсортирован по размеру в обратном порядке. То есть сверху самые тяжёлые, внизу самые лёгкие.

Подсказки

Хештеги