Desintercalar linhas de registro [duplicado]
Você herdou um servidor que executa vários aplicativos que geram o mesmo log.
Sua tarefa é desintercalar as linhas do arquivo de log por origem. Felizmente, cada linha começa com uma tag que indica de qual aplicativo ela é.
Histórico
Cada linha será parecida com isto:
[app_name] Something horrible happened!
- As tags de aplicativo estão sempre entre colchetes e conterão apenas caracteres alfanuméricos e sublinhados.
- Todas as linhas terão uma tag de aplicativo no início. Não haverá espaço em branco anterior ou qualquer outro caractere.
- Sempre haverá pelo menos um espaço após a tag do aplicativo
- As tags do aplicativo não estão vazias
- Pode haver outros colchetes posteriormente em qualquer linha.
- Pode haver ou não uma mensagem após a tag
- O log pode estar vazio
- Não há limite de quantas tags de aplicativo exclusivas estarão presentes no arquivo.
Exemplo
Um registro inteiro pode ter a seguinte aparência:
[weather] Current temp: 83F
[barkeep] Fish enters bar
[barkeep] Fish orders beer
[stockmarket] PI +3.14
[barkeep] Fish leaves bar
[weather] 40% chance of rain detected
Que deve gerar três registros diferentes:
[weather] Current temp: 83F
[weather] 40% chance of rain detected
[barkeep] Fish enters bar
[barkeep] Fish orders beer
[barkeep] Fish leaves bar
[stockmarket] PI +3.14
Os nomes das tags de aplicativo não são fornecidos a você com antecedência. Você deve determiná-los apenas analisando o arquivo de log.
Regras e pontuação
- Este é o código de golfe , então o código mais curto vence.
- Regras padrão e brechas se aplicam
- Use qualquer formato IO conveniente, desde que cada linha de entrada seja representada como uma string, não uma tag + mensagem pré-analisada. Lista não exaustiva de resultados permitidos:
- Vários arquivos nomeados após cada tag
- Várias listas de strings
- Uma lista concatenada de strings contendo linhas agrupadas por tag com ou sem separador (o separador não deve começar com uma tag)
- O mesmo que acima, mas para stdout ou um arquivo.
- A ordem em que os logs separados são produzidos é irrelevante, no entanto, as linhas de log dentro de cada grupo devem preservar a ordem em que foram encontradas no arquivo original
Respostas
R , 50 46 bytes
function(r)split(r,substr(r,1,regexpr("]",r)))
Produz como a list
com cada elemento name
d com [tag]
. Cada elemento da lista mantém a ordem em sua tag. Retorna uma lista nomeada named list()
vazia para entrada vazia.
-2 bytes cada graças a Robin Ryder e Dominic van Essen!
Pyth , 3 bytes
ohc
O formato de entrada é uma lista de strings:
["[weather] Current temp: 83F","[barkeep] Fish enters bar","[barkeep] Fish orders beer","[stockmarket] PI +3.14","[barkeep] Fish leaves bar","[weather] 40% chance of rain detected"]
Como funciona o código:
o
: Ordenar porh
: O primeiro elemento dec
: Cada string é dividida em espaços
Python , 44 bytes
lambda a:sorted(a,key=lambda l:l.split()[0])
O I / O frouxo nos permite obter e resultar em uma lista de linhas. Uma vez que não temos que separar os grupos, o problema é reduzido a realizar uma espécie de estável das linhas no prefixo de cada linha até o primeiro espaço, split()
irão se dividir em alguns outros caracteres de espaço em branco também, mas nenhum pode estar presente em a parte da tag do aplicativo.
APL (Dyalog Extended) , 10 bytes ( SBCS )
Função de prefixo tácito anônima. Obtém uma lista de listas de caracteres como argumento. Retorna uma matriz de listas de caracteres, com um log em cada linha.
⊢⊢⌸⍨≠⊃⍤⊆¨⊢
⊢
no argumento,
≠
use os não-espaços para ...
⊆¨
particionar cada lista em uma lista de listas (remove espaços, mantém execuções de não espaços),
⊃⍤
então mantenha o primeiro [de cada] (ou seja, as tags),
⊢⌸⍨
use-as como chaves para o grupo ...
⊢
o argumento
Scala, 26 bytes
_.sortBy(_.split("]")(0))
Retorna um List[String]
sem separador, mas é classificado pela tag.
Retorna um Map[String,List[String]]
, 26 bytes
_ groupBy(_.split("]")(0))
Obtém uma lista de strings e retorna um Map[List[String]]
onde as chaves são as tags e os valores são os logs associados a essa tag.
Solução anterior, 66 bytes
_ groupBy{case s"[$t]$r"=>t}map(_._2 mkString "\n")mkString "\n"*2
Experimente no Scastie (por qualquer motivo, s
não funciona no TIO)
Os logs de cada aplicativo são separados por 2 novas linhas (eu poderia economizar 2 bytes se fosse apenas um caractere de nova linha). A entrada é uma lista de strings e a saída é uma grande string.
05AB1E , 3 bytes
Σ#¬
Entrada e saída é uma lista de registros.
Explicação:
Σ#¬
Σ Sort by:
# Split (each log) by spaces
¬ Head (which is the tagname)
Isso também mantém a ordem dos logs, conforme necessário.
Retina 0.8.2 , 14 13 bytes
O$`(\w+).*
$1
Experimente online! Explicação: Como nenhum separador de grupo de saída é necessário, as linhas são simplesmente classificadas por tag de aplicativo, o que é obtido capturando a correspondência \w+
e especificando $1
como chave de classificação. A classificação na Retina é estável, para que as linhas com o mesmo prefixo mantenham sua ordem. Edit: Salvo 1 byte graças a @FryAmTheEggman por apontar uma maneira mais fácil de combinar a tag do aplicativo. Observe que embora a correspondência não inclua o entrelinhas [
, todas as linhas começam com [
, de modo que isso não afeta o resultado da classificação.
AWK , 62 58 bytes
Economizei 4 bytes graças a Dominic van Essen !!!
{a[$1][i++]=$0}END{for(k in a)for(j in a[k])print a[k][j]}
Armazena todas as linhas em uma matriz associativa 2D a
. A primeira chave é o primeiro campo (separado por um espaço em branco). Portanto, todas as linhas que começam com o mesmo campo são armazenadas juntas. A segunda chave é um índice inteiro crescente. A parte mais detalhada é a END
ação que imprime o conteúdo do a
agrupado pelo primeiro campo em ordem de aparecimento.
Io , 73 bytes
method(i,i map(split first)unique map(I,i select(split first==I))flatten)
Perl 6 , 16 bytes
*.sort:{~m/\w+/}
Classifica pela primeira string de caracteres alfanuméricos, que deve ser o nome do aplicativo
Python 3 , 148 127 bytes
a={}
try:
while 1:
b=input();c=b.split("]")[0]
if 1-(c in a):a[c]=[]
a[c]+=[b]
except:[print(e)for k in a for e in a[k]]
V (vim) , 5 bytes
úr/?]
Nota: O ?
código acima está no lugar do byte não imprimível \$\text{\x}81\$ (o caractere de controle "No Break Here").
Observe que isso funciona com a falta de espaços (mesmo um logo após o primeiro ]
colchete), com a presença de []
colchetes na mensagem de log e com a presença de um aplicativo não marcado. Experimente online!
Como?
úr/?]
ú - sort by:
r - with flag=r: use match (default behaviour is to use what's after the match)
/ - with the pattern:
? - (byte 83) a shortcut for .\{-}
. - match any character
\{-} - 0 or more times matching as few times as possible
] - match a literal ']' character
AutoHotkey, 74 bytes
Loop,Read,f
{
s:=A_LoopReadLine
FileAppend,%s%`n,% StrSplit(s,"]","[")[1]
}
Lê a partir de um arquivo nomeado f
e produz em vários arquivos com base na tag.
SimpleTemplate 0,84, 109 bytes
Sim, é bem longo, mas funciona!
{@callexplode intoL EOL,argv.0}{@eachL}{@if_ matches"@^(\[.*\])@"M}{@setS.[M.1]S.[M.1],_,EOL}{@/}{@/}{@echoS}
Este código gera um array com <old content>, line, <end of line>
.
{@echoS}
nivela automaticamente a matriz e a exibe.
Ungolfed:
Sim, é uma bagunça, mas aqui está uma versão mais limpa:
{@call explode into lines EOL, argv.0}
{@set storage null}
{@each lines as line}
{@if line matches "@^(\[.*\])@" match}
{@set storage.[match.1] storage.[match.1], line, EOL}
{@/}
{@/}
{@echo storage}
A função explode
é uma função PHP padrão, mas acessível na minha linguagem.
Você pode tentar isso em: http://sandbox.onlinephpfunctions.com/code/9c66f8bacc6315ae56e7c193170e430f9cf9d902
C # (.NET Core) , 181 162 160 bytes
input.GroupBy(l=>l.Split()[0]).ToList().ForEach((g)=>{using(var sw = new StreamWriter(g.Key.Trim('[').Trim(']')+".log")){foreach(var v in g)sw.WriteLine(v);}});
C # (compilador interativo do Visual C #) , 179 bytes
i=>i.GroupBy((l)=>{return l.Split(' ')[0];}).ToList().ForEach((g)=>{using(var sw = new StreamWriter(g.Key.Trim(new char[]{'[',']'})+".log")){foreach(var v in g)sw.WriteLine(v);}})
Não tenho certeza se a primeira solução é compatível com code gulf, então a segunda solução usa uma expressão lambda.
Ferrugem, 40 bytes
|a|a.sort_by_key(|x|x.split("]").next())
Faz uma referência mutável a uma fatia de strings e a classifica.
Perl 5 -M5.10.0 -Msort = estável, 53 bytes
say sort{(split('\]',$a))[0]cmp(split('\]',$b))[0]}<>