Сортировка целых чисел и вычисление среднего из топ-20 в командном файле - PullRequest
3 голосов
/ 18 августа 2011

Допустим, у меня есть пакетный файл, который читает произвольные целые числа из файла. Файл структурирован так, что каждая строка содержит одно целое число, например:

24
17
43
103
...

Мне нужно вычислить среднее из 20 верхних чисел в файле. Для этого мне нужна какая-то структура данных, которая хранит 20 верхних чисел. Однако, насколько я знаю, в пакетных файлах нет массивов. Возможно, мне придется прибегнуть к использованию временных файлов или к какому-либо другому методу, о котором я не знаю. Поэтому моя конечная цель - определить наилучший подход для реализации какого-либо алгоритма сортировки для пакетного файла и вычислить среднее из первых 20 целых чисел.

Есть ограничение, которое мне нужно наложить на проблему. Размер файла довольно велик (около 500 строк), поэтому я бы не стал использовать временные файлы из-за огромного количества выполненных операций чтения / записи (если, конечно, вы не можете убедить меня в обратном).

Ответы [ 4 ]

3 голосов
/ 18 августа 2011

Вы можете имитировать массивы в пакетном режиме.Взгляните на Использование массивов в пакетных файлах .

2 голосов
/ 19 августа 2011

В следующем решении используются массивы, как описано в статье по ссылке, приведенной в ответе @ Stoney.Он также использует заполнение нулями для правильной сортировки, что неплохо для @jeb, хотя в этом решении не используется команда sort.Вместо этого сортировка автоматически выполняется командой SET, выходные данные которой используются для итерации по «массиву».

@ECHO OFF
SET top=5

SET cnt=0
FOR /F %%N IN (datafile) DO CALL :insert %%N
IF %cnt%==0 GOTO :EOF

IF %cnt% LSS %top% (SET threshold=0) ELSE SET /A threshold=cnt-top

SET s=0
SET i=0

FOR /F "tokens=2 delims=.=" %%A IN ('SET __number.') DO CALL :calc %%A

SET /A res=s/(cnt-threshold)-1000000
ECHO Average is %res%
PAUSE
GOTO :EOF

:insert
SET /A n=1000000+%1
SET /A __number.%n%+=1
SET /A cnt+=1
GOTO :EOF

:calc
SET /A i_prev=i
SET /A i+=__number.%1
IF %i% LEQ %threshold% GOTO :EOF
IF %i_prev% GEQ %threshold% (
  SET /A s+=%1*__number.%1
) ELSE (
  SET /A "s+=%1*(i_prev+__number.%1-threshold)"
)

В основном, решение реализует следующий алгоритм:

  1. Выбор номеров из файла один за другим:

    1.1.Если число встречается впервые, добавьте его в массив со счетом 1.

    1.2.Если число является дубликатом уже добавленного номера, увеличьте соответствующее значение счетчика на 1.

    1.3.Увеличьте общее количество чисел на 1.

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

  3. Перебирать элементы массива следующим образом:

    3.1.Увеличьте индекс на текущее значение числа.

    3.2.Если индекс превышает порог:

    • Если он превысил порог на текущей итерации, увеличьте общую сумму на произведение числа и той части его счета, которая превысилаПорог.

    • Если порог был превышен ранее, увеличьте общую сумму на произведение числа и его количества.

    3.3.Если индекс не превышает пороговое значение, пропустите элемент.

  4. Рассчитайте среднее значение как общую сумму, деленную на разницу между общим счетом и порогом.

1 голос
/ 18 августа 2011

Вы можете использовать команду sort для сортировки чисел, но есть проблема, которая использует сортировку строк и не сортирует числа, поэтому 2 кажется больше 10.
Но это можно решить, если отформатировать все числа одинаковой длины во временный файл.
Итак, вы получите

024
017
043
103
...

Сортируйте их с помощью параметра / R (обратный), чтобы начать вывод с наибольшего числа.

Тогда вы можете просто прочитать 20 строк и построить среднюю сумму

0 голосов
/ 19 августа 2011

для маленьких файлов:

@Echo oFF

for /f %%a in (f1.txt) do Call :Append %%a
call :sort %sort%
pause
goto :EOF

:Append
call set sort=%%sort%% %*
goto :eof

:Sort
Setlocal EnableDelayedExpansion
Set/A n=1,s=0,c=s,r=s
for %%: In (%*) do (
    Set /a c+=1
    Set "nm.!c!=%%:")
:LP.1
if %s% EQU %c% Set/A n+=1,s=0
    Set/A s+=1
    Call :SPL %n% %s%
If %n% LEQ %c% goto :LP.1
:LP.2
    Echo:!nm.%c%!
    Set/A c-=1
If %c% GTR 0 goto :LP.2 
Endlocal & goto :EOF
:SPL
 If !nm.%1! GTR !nm.%2! (
   Set "t=!nm.%2!"&Set "nm.%2=!nm.%1!"
   Set "nm.%1=!t!"
 ) 
goto :EOF

или вариант:

 @echo off
 for /f %%# in (f1.txt) do (
    set x=##########%%#
    call set #%%x:~-0xa%%==)
 for /f "delims=#=" %%a in ('set ##') do echo(%%a
 pause 

есть также: сортировка по GNU

...