Условие
Нарисовать блок-схему, реализующую следующий алгоритм:
Дан входной файл INF с последовательным доступом (допускаются операции открытия и закрытия файла, проверка на конец файла, чтение текущей записи и перехода к следующей записи). Файл содержит записи одинаковой структуры, отсортированные в порядке возрастания значений целочисленного ключевого поля, содержащегося в записях. В файле INF могут находиться записи с одинаковыми значениями ключа. Требуется создать выходной файл OUTF, который формируется из входного файла INF по следующим правилам:
Если для некоторого значения ключа запись с этим значением ключевого
поля отсутствует в INF, то такой записи не должно быть и в файле OUTF.
Если для некоторого значения ключа в файле INF присутствует только
одна запись с таким значением ключевого поля, то эта запись должна
быть скопирована в файл OUTF.
Если для некоторого значения ключа в файле INF присутствует некоторое
нечетное количество записей с таким значением ключевого поля, то в
файл OUTF должна быть скопирована та запись из этого множества,
которая физически расположена в файле INF первой среди всех записей с
данным значением ключа.
Если для некоторого значения ключа в файле INF присутствует некоторое
четное количество записей с таким значением ключевого поля, то в файл
OUTF должна быть скопирована та запись из этого множества, которая
физически расположена в файле INF последней среди всех записей с
данным значением ключа.
Например:
INF: k2, k3, k4a, k4b, k4c, k8, k99a, k99b, k100a, k100b, k100c, k100d OUTF: k2, k3, k4a, k8, k99b, k100d.
Решение
Т.к. из условия неясно как именно записанны данные в файле (разделители, чем представляются пустые значения) я пропущу чтение и запись из файла. Тогда на вход нашего алгоритма вместо файла мы подадим коллекцию. Результатом то-же будет являться коллекция.
Вход: 2->nil 3->nil 4->'a' 4->'b' 4->'c' 8->nil 99->'a' 99->'b'
100->'a' 100->'b' 100->'c' 100->'d'.
Результат: 2->nil 3->nil 4->'a' 8->nil 99->'b' 100->'d'.
(input := OrderedCollection new) add: 2->nil; add: 3->nil; add: 4->'a'; add: 4->'b'; add: 4->'c'; add: 8->nil; add: 99->'a'; add: 99->'b'; add: 100->'a'; add: 100->'b'; add: 100->'c'; add: 100->'d'.
Собственно решение на Smalltalk-е:
(input groupedBy: [:each | each key] ) collect: [:each | each size even ifTrue: [each last] ifFalse: [each first] ]
Вот как это работает:
input - это наш вход.
input groupedBy: [:each | each key] - операция аналогичная group by в
SQL, условием группировки является ключевое поле.
Вот что в нашем случае вернет groupedBy:
2 -> #(2->nil) 3 -> #(3->nil) 4 -> #(4->a 4->b 4->c) 8 -> #(8 -> nil) 99 -> #(99->a 99->b) 100 -> #(100->a 100->b 100->c 100->d)
(each size \\ 2 = 0) ifTrue: [each last] ifFalse: [each first]
Если коллекция содержит кратное двум к-во элементов -
возвращается последний элемент, иначе первый.
Например для #(100->a 100->b 100->c 100->d) вернется последний
элемент, т.е. 100->d
А для (4->a 4->b 4->c) вернется первый элемент, т.е. 4->a.