Existe uma maneira de fazer algo assim:
$test_array = array("first_key" => "first_value",
"second_key" => "second_value");
var_dump(array_map(function($a, $b) { return "$a loves $b"; },
array_keys($test_array),
array_values($test_array)));
Mas, em vez de chamar array_keys
e array_values
passar diretamente a $test_array
variável?
A saída desejada é:
array(2) {
[0]=>
string(27) "first_key loves first_value"
[1]=>
string(29) "second_key loves second_value"
}
php
functional-programming
José Tomás Tocino
fonte
fonte
Respostas:
Não com o array_map, pois ele não manipula chaves.
array_walk faz:
No entanto, ele altera o array fornecido como parâmetro, portanto, não é exatamente uma programação funcional (como a pergunta foi marcada assim). Além disso, como apontado no comentário, isso alterará apenas os valores da matriz, para que as chaves não sejam as que você especificou na pergunta.
Você pode escrever uma função que corrige os pontos acima de si mesmo, se assim o desejar:
fonte
$a = "$b loves $a"
corresponder à saída desejada do OP.array_walk()
isso não é "programação funcional", já que não retorna a matriz resultante, mas um bool.Este é provavelmente o mais curto e fácil de raciocinar sobre:
fonte
array_keys()
. Isso parece um requisito bobo, no entanto.Aqui está minha solução muito simples e compatível com PHP 5.5:
A chamada que você fornece deve retornar uma matriz com dois valores, ou seja
return [key, value]
. A chamada interna para,array_map
portanto, produz uma matriz de matrizes. Isso é convertido novamente em uma matriz de dimensão única porarray_column
.Uso
Resultado
Aplicação parcial
Caso você precise usar a função várias vezes com matrizes diferentes, mas com a mesma função de mapeamento, é possível fazer algo chamado aplicativo de função parcial (relacionado a ' currying '), que permite transmitir apenas o array de dados após a chamada:
Que produz a mesma saída, dada
$func
e$ordinals
é a anterior.NOTA: se a sua função mapeada retornar a mesma tecla para duas entradas diferentes, o valor associado à tecla posterior ganhará. Inverta a matriz de entrada e o resultado da saída
array_map_assoc
para permitir que as chaves anteriores sejam vencidas. (As chaves retornadas no meu exemplo não podem colidir porque incorporam a chave da matriz de origem, que por sua vez deve ser única.)Alternativo
A seguir está uma variante do acima, que pode ser mais lógico para alguns, mas requer o PHP 5.6:
Nesta variante, sua função fornecida (sobre a qual a matriz de dados é mapeada) deve retornar uma matriz associativa com uma linha, ou seja
return [key => value]
. O resultado do mapeamento da chamada é simplesmente descompactado e passado paraarray_merge
. Como antes, o retorno de uma chave duplicada resultará na conquista de valores posteriores.Se você estiver no PHP 5.3 a 5.5, o seguinte é equivalente. Ele usa
array_reduce
e o+
operador de matriz binária para converter a matriz bidimensional resultante em uma matriz unidimensional, preservando as chaves:Uso
Ambas as variantes seriam usadas assim:
Observe o em
=>
vez de,
em$func
.A saída é a mesma de antes e cada uma pode ser parcialmente aplicada da mesma maneira que antes.
Resumo
O objetivo da pergunta original é tornar a chamada a mais simples possível, às custas de ter uma função mais complicada que é chamada; especialmente, ter a capacidade de transmitir a matriz de dados como um único argumento, sem dividir as chaves e os valores. Usando a função fornecida no início desta resposta:
Ou, apenas para esta pergunta, podemos simplificar a
array_map_assoc()
função que descarta as teclas de saída, pois a pergunta não as pede:Portanto, a resposta é NÃO , você não pode evitar ligar
array_keys
, mas pode abstrair o local em quearray_keys
é chamado para uma função de ordem superior, o que pode ser bom o suficiente.fonte
array_merge
porarray_replace
para preservar as chaves que seriam números inteiros.Com o PHP5.3 ou posterior:
fonte
É assim que eu implementei isso no meu projeto.
fonte
Olhe aqui! Existe uma solução trivial!
Como afirmado na pergunta,
array_map
já possui exatamente a funcionalidade necessária . As outras respostas aqui complicam seriamente demais as coisas:array_walk
não é funcional.Uso
Exatamente como você esperaria do seu exemplo:
fonte
qrrqy_keys()
não deve ser usada para # razõesPor "loop manual", quis dizer escrever uma função personalizada que usa
foreach
. Isso retorna uma nova matriz, comoarray_map
acontece porque o escopo da função faz$array
com que seja uma cópia - não uma referência:Sua técnica usando
array_map
with,array_keys
na verdade, parece mais simples e mais poderosa, porque você pode usarnull
como retorno de chamada para retornar os pares de valores-chave:fonte
unset( $value )
porque ele ainda existe no escopo definido.Com base na resposta da eis , aqui está o que eu fiz para evitar mexer na matriz original:
fonte
array_walk
pois não o está referenciando no encerramento.Eu fiz essa função, com base na resposta de eis :
Exemplo:
Resultado:
Obviamente, você pode usar
array_values
para retornar exatamente o que o OP deseja.fonte
$arr
do tipo array, no entanto, se você digitar seus argumentos comocallable
earray
poderá, em vez disso, soltar a verificação emis_callable
. Em seguida, você faz uma atribuição ao valor $ que não é usada. Você deve apenas ignorar o valor de retorno. Em terceiro lugar, seria melhor lançar uma exceção no retorno de chamada do que retornar false. Você sempre retornaria um valor válido ou sempre lançaria.A biblioteca do YaLinqo * é adequada para esse tipo de tarefa. É uma porta do LINQ from .NET que suporta totalmente valores e chaves em todos os retornos de chamada e se assemelha a SQL. Por exemplo:
ou apenas:
Aqui
'"$k loves $v"'
está um atalho para a sintaxe de fechamento completo, suportada por esta biblioteca.toArray()
no final é opcional. A cadeia de métodos retorna um iterador. Portanto, se o resultado precisar ser iterado usandoforeach
,toArray
chamada poderá ser removida.* desenvolvido por mim
fonte
Eu faria algo assim:
Resultados:
fonte
Adicionarei outra solução ao problema usando a versão 5.6 ou posterior. Não sei se é mais eficiente do que as já excelentes soluções (provavelmente não), mas para mim é mais simples de ler:
Usando
strval()
como uma função de exemplo noarray_map
, isso irá gerar:Espero que eu não seja o único que ache isso muito simples de entender.
array_combine
cria umakey => value
matriz a partir de uma matriz de chaves e de uma matriz de valores, o resto é bastante autoexplicativo.fonte
Você pode usar o método map nesta biblioteca de matrizes para obter exatamente o que deseja tão facilmente quanto:
também preserva chaves e retorna nova matriz, para não mencionar alguns modos diferentes para atender às suas necessidades.
fonte
Fonte
fonte
Eu sempre gosto da variante javascript do mapa de matriz. A versão mais simples seria:
Portanto, agora você pode passar uma função de retorno de chamada como construir os valores.
fonte
h(g(f($data)))
aplica - sef
, entãog
,h
ao seu dados. Geralmente, é considerado mais versátil na programação funcional ter uma função que execute a mesma operação em diversos dados do que ter uma função que aplique diversas funções a um conjunto de dados fixo.Outra maneira de fazer isso com a preservação de chaves (fora):
fonte
Vejo que falta a resposta óbvia:
Funciona exatamente como array_map. Quase.
Na verdade, não é puro
map
como você o conhece em outros idiomas. Php é muito estranho, portanto, requer algumas funções de usuário muito estranhas, pois não queremos desvendar nossaworse is better
abordagem precisamente quebrada .Realmente, não é realmente
map
. No entanto, ainda é muito útil.A primeira diferença óbvia do array_map é que o retorno de chamada obtém saídas de
each()
cada array de entrada, e não apenas do valor. Você ainda pode percorrer mais matrizes de uma só vez.A segunda diferença é a maneira como a chave é manipulada após retornar do retorno de chamada; o valor de retorno da função de retorno de chamada deve ser
array('new_key', 'new_value')
. As chaves podem e serão alteradas, as mesmas chaves podem até substituir o valor anterior, se a mesma chave for retornada. Esse não é ummap
comportamento comum , mas permite reescrever as chaves.A terceira coisa estranha é que, se você omitir o
key
valor de retorno (porarray(1 => 'value')
ouarray(null, 'value')
), a nova chave será atribuída, como se$array[] = $value
fosse usada. Esse também nãomap
é um comportamento comum, mas às vezes é útil, eu acho.A quarta coisa estranha é que, se a função de retorno de chamada não retornar um valor, ou retornar
null
, todo o conjunto de chaves e valores atuais é omitido na saída, é simplesmente ignorado. Esse recurso é totalmente unmap
py, mas tornaria essa função um excelente golpe para duplicararray_filter_assoc
, se houvesse essa função.Se você omitir o segundo elemento (
1 => ...
) (a parte do valor ) no retorno do retorno de chamada,null
será usado em vez do valor real.Quaisquer outros elementos, exceto aqueles com chaves
0
e1
no retorno de retorno de chamada, são ignorados.E, finalmente, se lambda retornar qualquer valor, exceto de
null
ou matriz, será tratado como se a chave e o valor fossem omitidos, portanto:null
é usado como seu valorNOTA:
Ao contrário de
array_map
, todos os parâmetros que não são de matriz passados paraarray_map_assoc
, com exceção do primeiro parâmetro de retorno de chamada, são convertidos silenciosamente em matrizes.EXEMPLOS:
// TODO: examples, anyone?
fonte