E vários parâmetros

15
function andMultipleExpr(){
  let logicalAnd;
  let i;
  for (i = 0; i < arguments.length; i++){
    logicalAnd =  arguments[i] && arguments[i+1];
  }
  return logicalAnd;
}

console.log(andMultipleExpr(true, true, false, false));

O que eu estou esperando é executar este código: true && true && false && false e isso deve retornar false .

Como fazer isso funcionar em js? obrigado

Hakim Asa
fonte
Estou apenas hesitando. Quero ter certeza se minha ideia está bem formulada. Se houver uma maneira melhor, por favor sugira.
Hakim Asa
Qual deve ser a saída quando os valores de Troothy são usados ​​em vez de booleanos? ou seja, andMultipleExpr(1, 1, 0, 0)ouandMultipleExpr(1, 1, 1, 1)
nick Zoum
Além disso, qual deve ser a saída de andMultipleExpr()(Chamando a função sem parâmetros)?
nick zoum 15/01
bem, esses casos também precisam ser levados em consideração. :-)
Hakim Asa

Respostas:

16

Use Array.prototype.everyem todos os argumentos passados ​​para verificar se todos são verdadeiros;

function andMultipleExpr(...a) {
  if(a.length === 0) return false; // return false when no argument being passed
  return a.every(Boolean);
}

console.log(andMultipleExpr(true, true, false)); // should return false
console.log(andMultipleExpr(true, true, true)); // should return true

Archie
fonte
Pode substituir e => e === trueporBoolean
nick zoum 15/01
@nickzoum isso corresponderia a todos os valores de verdade, o OP está comparando estritamente true.
Archie
11
@ Archie - Não, eles estão comparando verdade / falsidade. Não existe ===no código do OP. Sua everyideia é certa , no entanto. Mas apenas .every(e => e)faz o trabalho.
TJ Crowder
@TJCrowder sim, notei isso. Atualizada a resposta já. Obrigado :)
Archie
Se você adicionar uma função auxiliar: const isTrue = x => x === true(ou x => !!xpara todos os valores reais), poderá compactar sua solução return arguments.every(isTrue). O que para mim parece bonito.
mbojko 15/01
9

Você precisa

  1. Comece com logicalAnddefinido comotrue

  2. Use logicalAndao atualizá-lo, em vez de usar duas entradas dearguments

A mudança mínima é:

function andMultipleExpr(){
    let logicalAnd = true; // ***
    let i;
    for (i = 0; i < arguments.length; i++){
        logicalAnd = logicalAnd && arguments[i]; // ***
    }
    return logicalAnd;
}
console.log(andMultipleExpr(true, true, false, false));

Mas a solução da mbojko tem a vantagem de causar um curto-circuito (interromper o ciclo quando encontrar um valor falso), o que parece uma boa ideia.

Como você está usando o ES2015 +, você provavelmente deve usar um parâmetro rest em vez de argumentse pode usar um for-ofloop:

function andMultipleExpr(...flags) {
    let logicalAnd = true;
    for (const flag of flags) {
        logicalAnd = logicalAnd && flag;
    }
    return logicalAnd;
}
console.log(andMultipleExpr(true, true, false, false));

Você também pode causar um curto-circuito, de acordo com a abordagem da mbojko

function andMultipleExpr(...flags) {
    for (const flag of flags) {
        if (!flag) {
            return false;
        }
    }
    return true;
}
console.log(andMultipleExpr(true, true, false, false));

Algumas pessoas podem pensar reducenisso, mas a everysolução de Archie é muito melhor. (Mas, como sua comparação não é rigorosa, é só fazê-lo .every(flag => flag).)

T.J. multidão
fonte
11
Obrigado. Isso faz mais sentido para mim :-)
Hakim Asa
Não há necessidade de adicionar um segundo parâmetro na instrução de redução nesse caso, obter o primeiro parâmetro por padrão também funcionaria.
nick zoum 15/01
11
@nickzoum - Somente se pudermos assumir que a função nunca será chamada sem argumentos, pois [].reduce((a,b)=>a && b)lança.
TJ Crowder
6

Os retornos antecipados devem tornar o código mais eficiente e mais curto:

function andMultipleExpr() {
  for (let i = 0; i < arguments.length; i++) {
    if (!arguments[i]) {
      return false;
    }
  }

  return true;
}
mbojko
fonte
4

Eu acho que essa é uma maneira muito curta de usar o ES6 Array.prototype.reduce

let andMultipleExpr = (...args) => args.reduce((a, b) => a && b);

console.log(andMultipleExpr(true, true, false, false));

Para mais explicações sobre a função de redução, leia MDN

Patrissol Kenfack
fonte
Se você estiver usando um método de matriz, é muito melhor usar everycomo o Archie do que reduce. Mais simples, e curto-circuitos.
TJ Crowder
É verdade. Mas vamos ficar agora que ele quer, mas LÓGICO OU || agora com a redução, será apenas mudar && para ||
Patrissol Kenfack 15/01
Ou everypara some. Ainda mais simples. Ainda curto-circuito.
TJ Crowder
Bem feito. Você está certo @TJCrowder
Patrissol Kenfack
3

Você pode pegar Array#everye retornar o último valor.

Essa abordagem retorna o resultado real do AND lógico&& .

Usando a abordagem, é feito um curto-circuito para o primeiro valor encontrado de falsidade. Então a iteração pára.

function andMultipleExpr(...args) {
    var result; // any return value is configurable for empty args
    args.every(v => result = v);
    return result;
}

console.log(andMultipleExpr(true, true, false, false));
console.log(andMultipleExpr(true, true, 1, 2));
console.log(andMultipleExpr(true, 0, 1, 2));

Nina Scholz
fonte
3

Talvez você queira ouvir o que deu errado com o loop:

for (i = 0; i < arguments.length; i++){
  logicalAnd =  arguments[i] && arguments[i+1];
}
  1. esse loop armazena os &&dois últimos itens que encontra. No caso ideal, reuniria &&os dois últimos elementos da matriz (que já não é o que você precisa)
  2. além disso, no final do loop i=arguments.length-1, ele verifica o último elemento da matriz e i+1é o elemento "depois" do último, que é undefined. Em termos de relações lógicas, é considerado false, mas &&produz o valor em si mesmo, e é por isso que a função retorna undefinedo tempo todo (isso poderia ter sido mencionado na pergunta).

Documentos

expr1 && expr2: Se expr1pode ser convertido em true, retorna expr2; mais, retorna expr1.

arr=[true];
console.log("your case:",arr[0] && arr[1]);

console.log("1 && 2:", 1 && 2);


Em vez disso, você deve usar logicalAndcomo um acumulador, que coleta o resultado de &&todos os elementos anteriores, e um truque que você pode usar é se o resultado de uma parcial &&for false, não importa quais são os elementos restantes, o resultado final vai ser false, então o loop pode parar imediatamente:

function andMultipleExpr(){
    let logicalAnd = arguments[0] || false;
    for (let i = 1; i < arguments.length && logicalAnd; i++){
        logicalAnd = logicalAnd && arguments[i];
    }
    return logicalAnd;
}

console.log("():",andMultipleExpr());
console.log("(false):",andMultipleExpr(false));
console.log("(true):",andMultipleExpr(true));
console.log("(true,true):",andMultipleExpr(true,true));
console.log("(true, true, false, false):",andMultipleExpr(true, true, false, false));

e, em seguida, você pode otimizá-lo para a resposta de Archie : o resultado de &&itens -ing é truese todos os itens forem truee você não precisa executar uma única &&operação para calcular o resultado:

function andMultipleExpr(){
    if(arguments.length===0){
      return false;
    }
    for (let i = 0; i < arguments.length; i++){
      if(!arguments[i]){
        return false;
      }
    }
    return true;
}

console.log("():",andMultipleExpr());
console.log("(false):",andMultipleExpr(false));
console.log("(true):",andMultipleExpr(true));
console.log("(true,true):",andMultipleExpr(true,true));
console.log("(true, true, false, false):",andMultipleExpr(true, true, false, false));

(Nos trechos acima, pretendi produzir falsepara uma lista de argumentos vazia.)

tevemadar
fonte