Распечатайте / найдите первый символ (с НАИМЕНЬШИМ вхождением) в непустой строке, и порядок важен

BASH GNU bash, версия 4.2.46(2)-релиз (x86_64-redhat-linux-gnu)

Дана строка str, которая может хранить только любые нижние, UPPER или только числовые значения.

Как найти первый символ (с НАИМЕНЬШИМ вхождением) в непустой строкеstr? Задача состоит в том, чтобы напечатать буквуz, если сценарий такой (как можно быстрее, без ошибок, если данные находятся в строке или файле): https://repl.it/@asangal/find1stleastoccurrencecharmaintainorderanyleastsize



или Пример значенийstr:

str=aa, вывод должен быть 'a' (поскольку 'a' - единственный символ в строке - встречается 2 раза)

str=aa1, вывод должен быть '1' (поскольку '1' - это первый символ с наименьшим числом вхождений, равным 1)

str=aa1c1deef, вывод должен быть 'c' (поскольку 'c' стояла перед 'd' и оба имели 1 как наименьшее количество вхождений 1)

str=abcdeeddAbac, вывод должен быть 'A' (поскольку 'A' - это первый символ с меньшим числом вхождений, равным 1)

str=abcdeeddAbacA, вывод должен быть 'a' (поскольку 'a' - это первый символ с меньшим количеством вхождений, равным 2)

str=abcdeeddAbacAabc, вывод должен быть 'e' (поскольку 'e' - это первый символ с меньшим числом вхождений, равным 2)



Другой пример значения большого размера может быть:

str=axavzzzfdfdsldfnasdlkfjasdlkfjaslkfjasldkfjaslfjlasjkflasdkjfasdlfjasdljfasdkjfgio23yoryoiasyfoiywoerihlkdfhlaskdnkasdnvxcnvjzxkiivhaslyqwoyroiqwyroqwroqwlkasddlkkhaslkfjasdldkfjalsdkfashoqwiyroiqwyroiqwhrkjhajkdfhaslfkhasldkfh, вывод должен быть 'g' (поскольку 'g' - это первый символ с наименьшим числом вхождений, равным 1)



Ограничения / контекст:

  1. Значение может быть набором либо ниже, ВЕРХНИЙ или номер
  2. Строка всегда будет непустой; мы можем пока игнорировать любые символы типа пробела в значении.
  3. Найдите первую букву ([a-zA-Z0-9]), присутствующую вstrстрока с наименьшим количеством вхождений.
  4. Если возможно, я не хочу использовать какие-либо выражения (например, if-then-else), циклы (For/While) или пользовательские функции. Использование команд, библиотечных функций (если они доступны пользователю из коробки) - это нормально.

PS: Я знаю, что команды системного уровня вызывают все эти вещи за сценой, но я ищу минимальный код, если это возможно, в командной строке, например, $ prompt.

Я попробовал следующую уродливую не однострочную попытку, как указано ниже, здесь у меня есть цикл for,которого я хочу избежать, если это возможно, иsort команда помогает, но также заставляет меня терять порядок и не покрывает все условия.

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

str="axavzzzfdfdsldfnasdlkfjasdlkfjaslkfjasldkfjaslfjlasjkflasdkjfasdlfjasdljfasdkjfgio23yoryoiasyfoiywoerihlkdfhlaskdnkasdnvxcnvjzxkiivhaslyqwoyroiqwyroqwroqwlkasddlkkhaslkfjasdldkfjalsdkfashoqwiyroiqwyroiqwhrkjhajkdfhaslfkhasldkfh";
for char in $(echo $str | sed "s/\(.\)/\1\n/g" | grep .| tr '\012' ' '); 
do
    echo -n "$char=$(echo ${str} | sed "s/\(.\)/\1\n/g" | grep . | grep -c $char)";echo;
done | sort -u

Я считаю, что можно достичь того, что я ищу как однострочный (то есть с помощью набора общих команд и каналов Linux |) в BASH; просто хотел забрать себе мозг! Я знаю, что есть лучшие эксперты по оболочке, чем я.

Большинство решений, которые я нашел в Интернете, не поддерживают порядок (что для меня важно) и просто дают максимальное / меньшее количество / количество символов.

6 ответов

Решение

ОТВЕТ №4 - решение для использования файла /substr()/ с уменьшенным массивом

После некоторого обсуждения с @AKS и использования постоянно увеличивающегося набора данных (последний тест с использованием файла размером 36 МБ) awk/array возникла проблема с памятью (например, для большего набора данных различные awk ответы - до этого момента - требуется 6-8 ГБ ОЗУ).

Моя первая попытка решить проблему с памятью будет состоять в том, чтобы скопировать весь ввод в новую переменную; да, это означает копирование 36 МБ данных вawk переменной, но это все равно будет намного меньше, чем 6-8 ГБ ОЗУ.

Используя новый (более крупный) набор данных, предоставленный @AKS:

$ str="upvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLPlakjfaldsfpuFHAOOJJADFIASYDOYsggdhuafaismxasidfuasudfoasdufoiasudfoiayioOISYDOIQYORIYOIRYOIYQNOIYFAclamscvjlaivniauppruporupourpoupupovupuadouaouuouaudfaodfpadufuudofupuaspfupipoporqwooPOFPUnmcupauvpaupvouapouqweruuUPOUADUFUAUASDFLKHLP"
$ for i in {1..10}; do str="${str}${str}"; done
$ for i in {1..3}; do str="${str}${str}"; done
$ echo -e "\n\n-- Adding 'z' the only char in this big string blob 'str' variable'\n"
$ str="${str}z"
$ echo $str | wc
      1       1 36864002
$ echo "${str}" > newgiga.txt
$ ls -lh newgiga.txt
-rw-r--r--+ 1 xxxxx yyyyy 36M Jun  6 16:55 newgiga.txt

ПРИМЕЧАНИЕ. При создании этих данных все буквы / цифры встречаются более одного раза, кроме буквы.z (который появляется только один раз и в конце всего набора данных).

И новый / улучшенный awk решение:

$ time awk '
{ copy = copy $0                                 # make a copy of our input for later reparsing
  len = length($0)

  for ( i=1; i<=len; i++ ) {                     # get a count of occurrences of each letter/number
      token = substr($0,i,1)
      count[token]++
  }
}

END { for ( i in count ) {
          if ( min <= 0 ) 
              min = count[i]
          else
              min = count[i]<min?count[i]:min    # find the lowest/minimum count
      }

      for ( i=1; i<=len; i++ ) {                 # reparse input looking for first letter with count == min
          token = substr(copy,i,1)
          if ( min == count[token] ) {
              print token, min                   # print the letter/number and count and
              break                              # break out of our loop
          }
      }
    }
' newgiga.txt

z 1                                              # as mentioned in the above NOTE => z occurs just once in the dataset

real    0m19.575s                                # slightly better rate than the previous answer #3 that took 6 secs for 14 MB of data
user    0m19.406s
sys     0m0.171s

ПРИМЕЧАНИЕ. Этот ответ использовал 160 МБ памяти на моей машине (намного лучше, чем 6-8 ГБ в предыдущих ответах), а также работал примерно с той же скоростью, что и раньше.


Пробовал решение, устраняющее copyпеременная и вместо этого обрабатывает входной файл второй раз. Полученные результаты:

  • общее использование памяти снизилось на ~30 МБ (до ~130 МБ)
  • общее время работы увеличено на ~2 секунды

Итак, компромиссы на самом деле не стоят затраченных усилий.

EDIT2: в случае, если кому-то нужно знать минимальное значение, впервые появившееся символ / целое число и т.д. из всего Input_file, попробуйте выполнить следующее.

awk '
{
  num=split($0,array,"")
  for(i=1;i<=num;i++){
    ++count[array[i]]
  }
  for(j=1;j<=num;j++){
    tot_ind[count[array[j]]]=(tot_ind[count[array[j]]]?tot_ind[count[array[j]]] OFS:"")array[j]
  }
  for(i in count){
    min=min<=count[i]?(min?min:count[i]):count[i]
  }
}    
END{
  print "Minimum value found is:" min
  split(tot_ind[min],actual," ")
  print "All item(s) with same minimum values are:" actual[1]
}
'  Input_file


EDIT: поскольку OP получает ошибку, поэтому, несмотря на чтение из переменной, позволяет читать из Input_file, в случае, если OP считывает значения из Input_file, попробуйте выполнить следующее.

awk '
{
  delete tot_ind
  delete array
  delete count
  delete actual
  min=""
  num=split($0,array,"")
  for(i=1;i<=num;i++){
    ++count[array[i]]
  }
  for(j=1;j<=num;j++){
    tot_ind[count[array[j]]]=(tot_ind[count[array[j]]]?tot_ind[count[array[j]]] OFS:"")array[j]
  }
  for(i in count){
    min=min<=count[i]?(min?min:count[i]):count[i]
  }
  print "Minimum value found is:" min
  split(tot_ind[min],actual," ")
  print "All item(s) with same minimum values are:" actual[1]
}'  Input_file

Explanation: Добавление подробного объяснения вышеизложенного.

awk '                                                            ##Starting awk program from here.
{
  num=split($0,array,"")                                         ##Splitting current line into arrray with NULL delimiter.
  for(i=1;i<=num;i++){                                           ##Running loop to run till num here.
    ++count[array[i]]                                            ##Creating count array with index of valueof array and keep incrementing its value with 1.
  }
  for(j=1;j<=num;j++){                                           ##Running for loop till num here.
    tot_ind[count[array[j]]]=(tot_ind[count[array[j]]]?tot_ind[count[array[j]]] OFS:"")array[j]   ##Creating tot_ind with index of value of count array, this will have all values of minimum number here.
  }
  for(i in count){                                               ##Traversing in array count here.
    min=min<=count[i]?(min?min:count[i]):count[i]                ##Looking to get minimum value by comparing its value to each element.
  }
  print "Minimum value found is:" min                            ##Printing Minimum value here.
  split(tot_ind[min],actual," ")                                 ##Splitting tot_ind into actual array to get very first element of minimum value out of all values which have same minimum number.
  print "All item(s) with same minimum values are:" actual[1]    ##Printing very first minimum number here.
}' Input_file                                                    ##Mentioning Input_file name here.


Чтобы получить самое первое минимальное значение, которое встречается в Input_file(кстати, с помощью этого решения все элементы, которые имеют одинаковые минимальные значения, также могут быть напечатаны, с небольшими изменениями в последнем операторе печати этого кода). Написано и протестировано в GNUawk.

str="abcdeeddAbacA"
awk -v str="$str" '
BEGIN{
  num=split(str,array,"")
  for(i=1;i<=num;i++){
    ++count[array[i]]
  }
  for(j=1;j<=num;j++){
    tot_ind[count[array[j]]]=(tot_ind[count[array[j]]]?tot_ind[count[array[j]]] OFS:"")array[j]
  }
  for(i in count){
    min=min<=count[i]?(min?min:count[i]):count[i]
  }
    print "Minimum value found is:" min
    split(tot_ind[min],actual," ")
    print "All item(s) with same minimum values are:" actual[1]
}'

ДОКАЗАТЕЛЬСТВО концепции: пробежал выше с примерами OP.

./script.ksh aa
Minimum value found is:2
All item(s) with same minimum values are:a

./script.ksh aa1
Minimum value found is:1
All item(s) with same minimum values are:1

./script.ksh aa1c1deef
Minimum value found is:1
All item(s) with same minimum values are:c

./script.ksh abcdeeddAbac
Minimum value found is:1
All item(s) with same minimum values are:A

./script.ksh abcdeeddAbacA
Minimum value found is:2
All item(s) with same minimum values are:a

./script.ksh abcdeeddAbacAabc
Minimum value found is:2
All item(s) with same minimum values are:e

ПРИМЕЧАНИЕ. Я сохранил вышеупомянутое решение в файле сценария и передал образцы входных данных OP в качестве аргумента сценарию, OP мог использовать все, что пожелает, это было сделано, чтобы показать, как он работает.

ОТВЕТ №1 - решение на основе строки / переменной

Предполагая, что желаемая строка хранится в переменной str, вот один awk решение:

awk -v str="${str}" '
BEGIN { num = split(str,token,"")                # split str into an array of single letter/number elements

        for ( i=1; i<=num; i++ ) {               # get a count of occurrences of each letter/number
            count[token[i]]++
        }

        min = 10000000

        for ( i in count ) {
            min = count[i]<min?count[i]:min      # keep track of the lowest/minimum count
        }

        for ( i=1; i<=num; i++ ) {               # loop through array of letter/numbers
            if ( min == count[token[i]] ) {      # for the first letter/number we find where count = min
                print token[i], min              # print the letter/number and count and 
                break                            # then break out of our loop
            }
        }
      }'

Выполнение приведенного выше для разных строк образца:

++++++++++++++++ str = aa
a 2
++++++++++++++++ str = aa1
1 1
++++++++++++++++ str = aa1c1deef
c 1
++++++++++++++++ str = abcdeeddAbac
A 1
++++++++++++++++ str = abcdeeddAbacA
a 2
++++++++++++++++ str = abcdeeddAbacAabc
e 2
++++++++++++++++ str = axavzzzfdfdsldfnasdlkfjasdlkfjaslkfjasldkfjaslfjlasjkflasdkjfasdlfjasdljfasdkjfgio23yoryoiasyfoiywoerihlkdfhlaskdnkasdnvxcnvjzxkiivhaslyqwoyroiqwyroqwroqwlkasddlkkhaslkfjasdldkfjalsdkfashoqwiyroiqwyroiqwhrkjhajkdfhaslfkhasldkfh
g 1

ОТВЕТ №2 - решение на основе файлов / массивов

Глядя на комментарий OP к ответу RavinderSingh13 re: действительно большая строка находится в файле, и предполагая, что имя файла giga.txt...

Мы сможем внести незначительные изменения в предыдущий awk решение вроде такого:

awk '
BEGIN { RS = "\0" }                            # address files with no cr/lf
{ num = split($0,token,"")                     # split line/$0 into an array of single letter/number elements

  for( i=1; i<=num; i++ ) {                    # get a count of occurrences of each letter/number
      all[NR i] = token[i]                     # token array is for current line/$0 while all array is for entire file
      count[token[i]]++
  }
}

END { min = 10000000

      for ( i in count ) {
          min = count[i]<min?count[i]:min      # find the lowest/minimum count
      }

      for ( i in all ) {                       # loop through array of letter/numbers
          if ( min == count[all[i]] ) {        # for the first letter/number we find where count = min
              print all[i], min                # print the letter/number and count and 
              break                            # then break out of our loop
          }
      }
    }
' giga.txt

Размещение более длинного str образец в giga.txt:

$ cat giga.txt
axavzzzfdfdsldfnasdlkfjasdlkfjaslkfjasldkfjaslfjlasjkflasdkjfasdlfjasdljfasdkjfgio23yoryoiasyfoiywoerihlkdfhlaskdnkasdnvxcnvjzxkiivhaslyqwoyroiqwyroqwroqwlkasddlkkhaslkfjasdldkfjalsdkfashoqwiyroiqwyroiqwhrkjhajkdfhaslfkhasldkfh

Выполнение вышеуказанного awk решение против giga.txt дает нам:

$ awk '....' giga.txt
g 1

ОТВЕТ № 3 - решение на основе файла /substr()

OP предоставил дополнительные сведения о том, как создать "большой" файл данных:

$ ls lR / > giga.txt       # I hit ^C after ~20 secs
$ sed  "s/\(.\)/\1\n/g" giga.txt | grep -o [a-zA-Z0-9] | tr -d '\012' > newgiga.txt       # remove all but letters and numbers

Это дало мне файл из 14 миллионов символов (newgiga.txt).

Я провел несколько тестов по времени вместе с новым awk решение (см. ниже) против файла с 14 миллионами символов и придумал следующие тайминги:

  • 15 секунд с файлом / массивом на основеawk решение (см. мой предыдущий ответ - выше)
  • 25 секунд с OP sed/grep/echo/uniq/tr/sort ответ
  • 4+ минут с RavinderSingh13's awk решение (на самом деле нажмите ^C через 4 минуты)
  • 6 секунд с новым файлом /substr() на основеawk решение (см. ниже)

ПРИМЕЧАНИЕ. Все решения работают с моимnewgiga.txt файл окончательный ответ был письмом Z (365 случаев).

Заменив split/array код с серией substr() звонков и внесения небольших изменений в то, как allмассив проиндексирован, мне удалось сократить время работы предыдущего файла / массива на ~60% на основеawk решение:

awk '
BEGIN { RS = "\0" }
{ len=length($0)

  for( i=1; i<=len; i++ ) {                    # get a count of occurrences of each letter/number
      token=substr($0,i,1)
      a++
      all[a] = token                           # token array is for current line/$0 while all array is for entire file
      count[token]++
  }
}

END { min=10000000

      for( i in count ) {
          min = count[i]<min?count[i]:min      # find the lowest/minimum count
      }

      for( i in all ) {                        # loop through array of letter/numbers
          if ( min == count[all[i]] ) {        # for the first letter/number we find where count = min
              print all[i], min                # print the letter/number and count and
              break                            # break out of our loop
          }
      }
    }
' newgiga.txt

ПРИМЕЧАНИЕ: Честно говоря, я не ожидалsubstr() призывает быть быстрее, чем split/array метод но я предполагаю awk имеет довольно быстрый встроенный метод для запуска substr() звонки.

Если файл умещается в памяти:

<file tr -dc '[:alnum:]' | perl -ln0777e 'while (($c=substr $_,0,1) ne q{}) {$n=eval "y/\Q$c\E//d"; $count{$n}=$count{$n}.$c} END{for (sort {$a <=> $b} keys %count) {print substr $count{$_},0,1; exit}}'

Пытаться

grep -o . <<<  ${str} |  cat -n | sort -k2  | uniq -c -f1 |  sort -nr -k1 -k2 | sed 's/.*[ \t]//g;$!d'

Демо:

$str=aa
$grep -o . <<<  ${str} |  cat -n | sort -k2  | uniq -c -f1 |  sort -nr -k1 -k2 | sed 's/.*[ \t]//g;$!d' 
a
$str=aa1
$grep -o . <<<  ${str} |  cat -n | sort -k2  | uniq -c -f1 |  sort -nr -k1 -k2 | sed 's/.*[ \t]//g;$!d' 
1
$str=aa1c1deef
$grep -o . <<<  ${str} |  cat -n | sort -k2  | uniq -c -f1 |  sort -nr -k1 -k2 | sed 's/.*[ \t]//g;$!d' 
c
$str=abcdeeddAbac
$grep -o . <<<  ${str} |  cat -n | sort -k2  | uniq -c -f1 |  sort -nr -k1 -k2 | sed 's/.*[ \t]//g;$!d' 
A
$str=abcdeeddAbacA
$grep -o . <<<  ${str} |  cat -n | sort -k2  | uniq -c -f1 |  sort -nr -k1 -k2 | sed 's/.*[ \t]//g;$!d' 
e
$str=abcdeeddAbacAabc
$grep -o . <<<  ${str} |  cat -n | sort -k2  | uniq -c -f1 |  sort -nr -k1 -k2 | sed 's/.*[ \t]//g;$!d' 
e
$str=axavzzzfdfdsldfnasdlkfjasdlkfjaslkfjasldkfjaslfjlasjkflasdkjfasdlfjasdljfasdkjfgio23yoryoiasyfoiywoerihlkdfhlaskdnkasdnvxcnvjzxkiivhaslyqwoyroiqwyroqwroqwlkasddlkkhaslkfjasdldkfjalsdkfashoqwiyroiqwyroiqwhrkjhajkdfhaslfkhasldkf
$grep -o . <<<  ${str} |  cat -n | sort -k2  | uniq -c -f1 |  sort -nr -k1 -k2 | sed 's/.*[ \t]//g;$!d' 
g
$


Изменить: в приведенном ниже случае

str=abcdeeddAbacA, вывод должен быть 'a' (поскольку 'a' - это первый символ с меньшим количеством вхождений, равным 2)

ee идет раньше a

Хорошо, я думаю, что наконец-то получил (съел 3 миски морковного пудинга в 5 часов утра); Я был мотивирован!! всеми вами.

  • Нет for петли или if-then используемые условные выражения.
  • Во время операции не создается переменная.
  • С помощью timeперед следующим решением - показывает, что он завершен для самого большого файла, который у меня был менее 1,5 секундreal 0m1.428s; в то времяawkрешение с использованием файла заняло около 4,5 секунд).
  • Больше похоже на однострочный (использование толькоLinux commands а также | трубы).

Любые комментарии приветствуются (если я пропустил какой-либо вариант использования).

$ echo $str | egrep -o . | \
  egrep $(echo $str | grep -o [a-zA-Z0-9] | sort | uniq -c | \
    grep " $(echo $str | grep -o [a-zA-Z0-9] | sort | uniq -c| sort -n -k1 | head -1 | grep -ow " [0-9][0-9]*") " | \
  sed "s/^[ \t][ \t]*//"|cut -d' ' -f2 | tr '\012' '|' | sed "s/.$//") | head -1

Будет выведена только буква (alnum).

Если кто-то хочет увидеть подсчет (вид вне области видимости), он может изменить -f2 к -f1 в приведенной выше команде вырезания.

Вот сценарий: https://repl.it/@asangal/find1stleastoccurrencecharmaintainorderanyleastsize

Другие вопросы по тегам