파일을 가장 큰 파일의 평균 크기로 그룹화

파일을 가장 큰 파일의 평균 크기로 그룹화

6개의 파일이 있고 평균 크기에 따라 2~3개로 그룹화하고 싶습니다.

file1.log 50G
file2.log 40G
file3.log 20G
file4.log 10G
file5.log 30G
file6.log 70G

File6이것은 70G가장 큰 파일이며 가장 큰 파일을 기준으로 나머지 파일을 그룹화하고 싶습니다.

출력은 다음과 같아야 합니다.

  1. 1로 그룹화하면 모든 파일이 포함되어야 합니다. - 병렬 1
  2. 2로 그룹화 - 병렬 2

출력 1

file4.log 10G
file5.log 30G
file6.log 70G

출력 2

file1.log 50G
file2.log 40G
file3.log 20G

두 파일의 평균은 동일합니다.

세 번째 병렬 3 세트는 다음과 같습니다.

출력 1

file6.log 70G

출력 2

file1.log 50G
file3.log 20G

출력 3

file2.log 40G
file4.log 10G
file5.log 30G

정확한 평균일 필요는 없으며 가능한 가장 가까운 평균으로 파일을 나누면 됩니다.

감사해요! !

답변1

#!/usr/bin/env zsh

# To care about hidden filenames:
#setopt GLOB_DOTS

# Load the zstat builtin
zmodload -F zsh/stat b:zstat

# Get the regular files in the current directory,
# ordered by size (largest first)
files=( ./*(.OL) )

# Precalculate the filesizes
typeset -A filesizes
for file in "${files[@]}"; do
    filesizes[$file]=$( zstat +size "$file" )
done

# The maximum size of a bin is the size of the largest file
maxsize=${filesizes[${files[1]}]}

binsizes=()
typeset -A filebins
for file in "${files[@]}"; do
    filesize=${filesizes[$file]}
    bin=1   # try fitting into first bin first
    ok=0    # haven't yet found a bin for this file
    for binsize in "${binsizes[@]}"; do
        if (( filesize + binsize <= maxsize )); then
            # File fits in this bin,
            # update bin size and place file in bin
            binsizes[$bin]=$(( filesize + binsize ))
            filebins[$file]=$bin
            ok=1    # now we're good
            break
        fi
        # Try next bin
        bin=$(( bin + 1 ))
    done

    if [ "$ok" -eq 0 ]; then
        # Wasn't able to fit file in existing bin,
        # create new bin
        binsizes+=( "$filesize" )
        filebins[$file]=${#binsizes[@]}
    fi
done

# Do final output
printf 'Bin max size = %d\n' "$maxsize"
for file in "${files[@]}"; do
    printf '%d: %s (file size=%d / bin size=%d)\n' "${filebins[$file]}" "$file" \
        "${filesizes[$file]}" "${binsizes[$filebins[$file]]}"
done | sort -n

위의 zsh쉘 스크립트는 현재 디렉토리의 모든 파일을 비닝하며 최대 비닝 크기는 다음을 기반으로 합니다.엄격하게최대 파일 크기. 파일이 크기가 작은 순서로 정렬되는 우선순위 적응 알고리즘을 구현합니다. 이것이 소위 "FFD" 알고리즘이다Wikipedia 기사 "복싱 문제". "MFFD" 알고리즘의 구현은 간단하지 않으며 zsh200줄 미만의 코드가 필요하므로 여기에 게시하지 않겠습니다.

시험:

$ ls -l
total 450816
-rw-r--r--  1 kk  wheel  10485760 Jan 19 23:53 file-10.log
-rw-r--r--  1 kk  wheel  20971520 Jan 19 23:53 file-20.log
-rw-r--r--  1 kk  wheel  31457280 Jan 19 23:53 file-30.log
-rw-r--r--  1 kk  wheel  41943040 Jan 19 23:53 file-40.log
-rw-r--r--  1 kk  wheel  52428800 Jan 19 23:53 file-50.log
-rw-r--r--  1 kk  wheel  73400320 Jan 19 23:53 file-70.log
$ zsh ../script.sh
Bin max size = 73400320
1: ./file-70.log (file size=73400320 / bin size=73400320)
2: ./file-20.log (file size=20971520 / bin size=73400320)
2: ./file-50.log (file size=52428800 / bin size=73400320)
3: ./file-30.log (file size=31457280 / bin size=73400320)
3: ./file-40.log (file size=41943040 / bin size=73400320)
4: ./file-10.log (file size=10485760 / bin size=10485760)

위의 각 줄 시작 부분에 있는 숫자는 파일에 할당된 bin 번호에 해당합니다.

답변2

이것은 거의 동등한 것 같습니다.박스 포장질문.

Bin Packing 문제는 NP 하드이므로 이를 수행하는 알려진 지름길은 없습니다. 무차별 대입(이미 너무 큰 그룹에 더 많은 파일을 추가하는 것과 같은 어리석은 시도를 제외하고 합리적인 순서로 모든 옵션을 시도)이 실행 가능한 방법입니다.

6개의 파일을 사용하는 경우 무차별 대입 접근 방식은 가능한 모든 그룹을 수동으로 나열하고, 파일 사용량을 분할하는 방법을 계산하고, 최소 최대 그룹 크기를 제공하는 그룹을 선택하면 될 만큼 간단해야 합니다.

관련 정보