Como obter valores distintos de uma matriz de objetos em JavaScript?


384

Supondo que tenho o seguinte:

var array = 
    [
        {"name":"Joe", "age":17}, 
        {"name":"Bob", "age":17}, 
        {"name":"Carl", "age": 35}
    ]

Qual é a melhor maneira de obter uma matriz de todas as idades distintas, para que eu obtenha uma matriz de resultados de:

[17, 35]

Existe alguma maneira de estruturar alternativamente os dados ou um método melhor, de modo que não precise iterar através de cada matriz verificando o valor de "idade" e verificando se existe outra matriz em relação a outra matriz e adicioná-lo, se não?

Se houvesse alguma maneira, eu poderia retirar as idades distintas sem iterar ...

Atual maneira ineficiente que gostaria de melhorar ... Se isso significa que, em vez de "matriz" ser uma matriz de objetos, mas um "mapa" de objetos com alguma chave exclusiva (ou seja, "1,2,3") que seria ok também Estou apenas procurando a maneira mais eficiente de desempenho.

A seguir, é como eu faço isso atualmente, mas para mim, a iteração parece pouco exigente em termos de eficiência, mesmo que funcione ...

var distinct = []
for (var i = 0; i < array.length; i++)
   if (array[i].age not in distinct)
      distinct.push(array[i].age)

34
a iteração não é "ruim para a eficiência" e você não pode fazer nada com todos os elementos "sem iterar". você pode usar vários métodos de aparência funcional, mas, finalmente, algo em algum nível precisa percorrer os itens.
Eevee

// código 100% em execução const listOfTags = [{id: 1, label: "Hello", cor: "red", classificação: 0}, {id: 2, label: "World", cor: "green", classificação : 1}, {id: 3, label: "Hello", cor: "blue", classificação: 4}, {id: 4, label: "Sunshine", cor: "yellow", classificação: 5}, {id : 5, label: "Hello", cor: "red", classificação: 6}], keys = ['label', 'color'], filtradas = listOfTags.filter ((s => o => (k => ! s.has (k) && s.add (k)) (keys.map (k => o [k]). join ('|'))) (novo conjunto)); console.log (filtrado);
Sandeep Mishra

11
a recompensa é ótima, mas a pergunta com os dados e a resposta já foi respondida aqui: stackoverflow.com/questions/53542882/… . qual é o propósito da recompensa? devo responder esse problema específico com duas ou mais chaves?
Nina Scholz

Setobjeto mapes são um desperdício. Este trabalho assume apenas uma .reduce()etapa simples .
Redu

Respostas:


127

Se esse fosse o PHP, eu construí uma matriz com as chaves e pegava array_keysno final, mas JS não tem esse luxo. Em vez disso, tente o seguinte:

var flags = [], output = [], l = array.length, i;
for( i=0; i<l; i++) {
    if( flags[array[i].age]) continue;
    flags[array[i].age] = true;
    output.push(array[i].age);
}

15
Não, porque array_uniquecompararia o item inteiro, não apenas a idade, como é solicitado aqui.
Niet the Dark Absol

6
Eu acho que flags = {}é melhor do queflags = []
zhuguowei

3
@zhuguowei talvez, embora não há nada realmente errado com matrizes esparsas - e eu também assumiu que ageé um relativamente pequeno número inteiro (<120 certamente)
Niet the Dark Absol

como também podemos imprimir o número total de pessoas com a mesma idade?
user1788736

606

Se você estiver usando o ES6 / ES2015 ou posterior, poderá fazê-lo desta maneira:

const unique = [...new Set(array.map(item => item.age))];

Aqui está um exemplo de como fazê-lo.


11
Eu recebo um erro:TypeError: (intermediate value).slice is not a function
AngJobs on Github 13/07

7
@ Thomas ... significa operador de propagação. Nesse caso, significa criar um novo conjunto e espalhá-lo em uma lista. Você pode encontrar mais sobre ele aqui: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
Vlad Bezden

10
para texto datilografado, você deve usar o novo conjunto agrupado em Array.from () ... fornecerei a resposta abaixo. @AngJobs
Christian Matthew

4
é possível descobrir objetos únicos com base em várias chaves no objeto?
Jefree Sujit #

14
Esta solução foi fornecida quase literalmente alguns meses antes pelo @Russell Vea. Você verificou as respostas existentes? Mas, novamente, mais de 266 votos mostram que ninguém mais verificou.
Dan Dascalescu 28/09

165

usando ES6

let array = [
  { "name": "Joe", "age": 17 },
  { "name": "Bob", "age": 17 },
  { "name": "Carl", "age": 35 }
];
array.map(item => item.age)
  .filter((value, index, self) => self.indexOf(value) === index)

> [17, 35]

2
Se eu quiser obter o valor com seu índice, como posso obter Exemplo: Quero obter {"name": "Bob", "age": "17"}, {"name": "Bob", "age ":" 17 "}
Abdullah Al Mamun

10
É por isso que você tem que manter a rolagem
Alejandro Bastidas

5
@AbdullahAlMamun, você pode usar o mapa no .filter em vez de chamar o .map primeiro, desta forma:array.filter((value, index, self) => self.map(x => x.age).indexOf(value.age) == index)
Leo

11
ps: dentro .map .filter pode ser lento, por isso tome cuidado com grandes matrizes
Leo

2
@IvanNosov seu trecho é muito bom, embora várias linhas de explicação sobre como ele funciona com ponteiros para mapear e documentação filtro irá torná-lo perfeito e limpar para iniciantes
azakgaim

128

Você pode usar uma abordagem de dicionário como esta. Basicamente, você atribui o valor que deseja diferenciar como chave no "dicionário" (aqui usamos uma matriz como objeto para evitar o modo de dicionário). Se a chave não existir, adicione esse valor como distinto.

Aqui está uma demonstração de trabalho:

var array = [{"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35}];
var unique = [];
var distinct = [];
for( let i = 0; i < array.length; i++ ){
  if( !unique[array[i].age]){
    distinct.push(array[i].age);
    unique[array[i].age] = 1;
  }
}
var d = document.getElementById("d");
d.innerHTML = "" + distinct;
<div id="d"></div>

Será O (n) onde n é o número de objetos na matriz emm é o número de valores únicos. Não existe uma maneira mais rápida que O (n) porque você deve inspecionar cada valor pelo menos uma vez.

A versão anterior disso usava um objeto, e para dentro. Eles eram de natureza menor e, desde então, foram atualizados de maneira menor acima. No entanto, o motivo de um aparente avanço no desempenho entre as duas versões no jsperf original foi devido ao tamanho da amostra de dados ser tão pequeno. Portanto, a principal comparação na versão anterior foi analisar a diferença entre o uso interno do mapa e do filtro e as pesquisas no modo de dicionário.

Atualizei o código acima, conforme observado, no entanto, também atualizei o jsperf para examinar 1000 objetos em vez de 3. 3 negligenciou muitas das armadilhas de desempenho envolvidas ( jsperf obsoleto ).

atuação

https://jsperf.com/filter-vs-dictionary-more-data Quando executei este dicionário, foi 96% mais rápido.

filtro vs dicionário


4
rápido e sem necessidade de plugins adicionais. Realmente legal
mihai

2
e quantoif( typeof(unique[array[i].age]) == "undefined"){ distinct.push(array[i].age); unique[array[i].age] = 0; }
Timeless

7
Uau, o desempenho realmente mudou em favor da opção de mapa. Clique no link jsperf!
NO

11
@ 98percentmonkey - O objeto foi usado para facilitar a "abordagem de dicionário". Dentro do objeto, cada ocorrência rastreada é adicionada como uma chave (ou uma lixeira). Dessa forma, quando nos deparamos com uma ocorrência, podemos verificar se a chave (ou compartimento) existe; se existe, sabemos que a ocorrência não é única - se não existe, sabemos que a ocorrência é única e a adicionamos. #
Travis J #

11
@ 98percentmonkey - O motivo para usar um objeto é que a pesquisa é O (1), uma vez que verifica o nome de uma propriedade uma vez, enquanto uma matriz é O (n), pois é necessário examinar todos os valores para verificar a existência. No final do processo, o conjunto de chaves (posições) no objeto representa o conjunto de ocorrências exclusivas.
Travis J

91

É assim que você resolveria isso usando o novo conjunto via ES6 para texto datilografado em 25 de agosto de 2017

Array.from(new Set(yourArray.map((item: any) => item.id)))

3
isso ajudou, estava ficando antes obrigado. Digite 'Set' não é um tipo de matriz
Robert King

11
Esta é uma ótima resposta. Até que eu rolei para baixo, escrevi uma resposta dizendo: Object.keys (values.reduce <any> ((x, y) => {x [y] = null; return x;}, {} )); Mas essa resposta é mais concisa e se aplica a todos os tipos de dados em vez de apenas cadeias.
jgosar

11
esta resposta é espetacular!
lukeocodes

79

Usando os recursos do ES6, você pode fazer algo como:

const uniqueAges = [...new Set( array.map(obj => obj.age)) ];

6
Essa abordagem funcionará apenas em tipos primitivos (que é o caso aqui, pois as idades são uma matriz de números), mas falhará nos objetos.
k0pernikus

alguma idéia de como fazê-lo funcionar para objetos com duas chaves?
Cegprakash 5/09/19

11
Algo comoconst uniqueObjects = [ ...new Set( array.map( obj => obj.age) ) ].map( age=> { return array.find(obj => obj.age === age) } )
Harley B

62

Acabei de mapear e remover dups:

var ages = array.map(function(obj) { return obj.age; });
ages = ages.filter(function(v,i) { return ages.indexOf(v) == i; });

console.log(ages); //=> [17, 35]

Edit: Aight! Não é a maneira mais eficiente em termos de desempenho, mas a IMO mais simples e legível. Se você realmente se preocupa com a micro-otimização ou possui enormes quantidades de dados, um forloop regular será mais "eficiente".


3
@elclanrs - "a maneira mais eficiente em termos de desempenho" - Essa abordagem é lenta .
Travis J

11
@Eevee: Entendo. A versão sublinhada na sua resposta também não é muito rápida , no final das contas, você escolhe o que é mais conveniente, duvido que 1-30% mais ou menos reflita "grande melhoria" em testes genéricos e quando os OP / s estão na casa dos milhares .
Elclanrs 28/02

4
bem, claro. com apenas três elementos , o mais rápido é criar três variáveis ​​e usar alguns ifs. você obterá resultados muito diferentes com três milhões.
Eevee

11
não rápido, mas no meu caso, ele fez o truque, pois não estou lidando com um grande conjunto de dados, obrigado.
Felipe Alarcon

37
var unique = array
    .map(p => p.age)
    .filter((age, index, arr) => arr.indexOf(age) == index)
    .sort(); // sorting is optional

// or in ES6

var unique = [...new Set(array.map(p => p.age))];

// or with lodash

var unique = _.uniq(_.map(array, 'age'));

Exemplo ES6

const data = [
  { name: "Joe", age: 17}, 
  { name: "Bob", age: 17}, 
  { name: "Carl", age: 35}
];

const arr = data.map(p => p.age); // [17, 17, 35]
const s = new Set(arr); // {17, 35} a set removes duplications, but it's still a set
const unique = [...s]; // [17, 35] Use the spread operator to transform a set into an Array
// or use Array.from to transform a set into an array
const unique2 = Array.from(s); // [17, 35]

6
Embora esse código possa responder à pergunta, fornecer um contexto adicional sobre como e por que resolve o problema melhoraria o valor a longo prazo da resposta.
Alexander

O primeiro que está usando o indexOf vs o índice é simplesmente brilhante.
alas

Observe que isso funciona apenas para valores primitivos. Se você tiver uma matriz de datas, precisará de alguns métodos mais personalizados. Leia mais aqui: codeburst.io/javascript-array-distinct-5edc93501dc4
Molx

36

Para quem deseja retornar objeto com todas as propriedades exclusivas por chave

const array =
  [
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
  ]

const key = 'age';

const arrayUniqueByKey = [...new Map(array.map(item =>
  [item[key], item])).values()];

console.log(arrayUniqueByKey);

   /*OUTPUT
       [
        { "name": "Bob", "age": 17 },
        { "name": "Carl", "age": 35 }
       ]
   */

 // Note: this will pick the last duplicated item in the list.


2
Nota: isso selecionará o último item duplicado na lista.
Eugene Kulabuhov 19/01

11
Adicionando isso à resposta!
Arun Kumar Saini 20/01

11
Exatamente o que eu estava procurando. Muito obrigado por compartilhar!
Devner 16/03

11
Eu acho que essa deve ser a melhor resposta para ser honesto!
Jaroslav Benc

26

Já existem muitas respostas válidas, mas eu queria adicionar uma que use apenas o reduce()método, pois é limpo e simples.

function uniqueBy(arr, prop){
  return arr.reduce((a, d) => {
    if (!a.includes(d[prop])) { a.push(d[prop]); }
    return a;
  }, []);
}

Use-o assim:

var array = [
  {"name": "Joe", "age": 17}, 
  {"name": "Bob", "age": 17}, 
  {"name": "Carl", "age": 35}
];

var ages = uniqueBy(array, "age");
console.log(ages); // [17, 35]

20

A forEachversão da resposta do @ travis-j (útil em navegadores modernos e no mundo do Node JS):

var unique = {};
var distinct = [];
array.forEach(function (x) {
  if (!unique[x.age]) {
    distinct.push(x.age);
    unique[x.age] = true;
  }
});

34% mais rápido no Chrome v29.0.1547: http://jsperf.com/filter-versus-dictionary/3

E uma solução genérica que usa uma função de mapeador (um pouco mais lenta que o mapa direto, mas isso é esperado):

function uniqueBy(arr, fn) {
  var unique = {};
  var distinct = [];
  arr.forEach(function (x) {
    var key = fn(x);
    if (!unique[key]) {
      distinct.push(key);
      unique[key] = true;
    }
  });
  return distinct;
}

// usage
uniqueBy(array, function(x){return x.age;}); // outputs [17, 35]

11
Gosto mais da solução genérica, pois é improvável que a idade seja o único valor distinto necessário em um cenário do mundo real.
Toft

5
No genérico, altere "distinct.push (key)" para "distinct.push (x)" para retornar uma lista dos elementos reais, que eu acho altamente úteis!
Silas Hansen

15

Comecei a colocar o Underscore em todos os novos projetos por padrão, apenas para nunca ter que pensar nesses pequenos problemas de troca de dados.

var array = [{"name":"Joe", "age":17}, {"name":"Bob", "age":17}, {"name":"Carl", "age": 35}];
console.log(_.chain(array).map(function(item) { return item.age }).uniq().value());

Produz [17, 35].


13

Aqui está outra maneira de resolver isso:

var result = {};
for(var i in array) {
    result[array[i].age] = null;
}
result = Object.keys(result);

Não faço ideia do quão rápido essa solução é comparada às outras, mas gosto do visual mais limpo. ;-)


EDIT: Ok, o acima parece ser a solução mais lenta de todos aqui.

Criei um caso de teste de desempenho aqui: http://jsperf.com/distinct-values-from-array

Em vez de testar para as idades (Inteiros), optei por comparar os nomes (Strings).

O método 1 (solução da TS) é muito rápido. Curiosamente, o Método 7 supera todas as outras soluções. Aqui, acabei de me livrar do .indexOf () e usei uma implementação "manual", evitando a chamada de função em loop:

var result = [];
loop1: for (var i = 0; i < array.length; i++) {
    var name = array[i].name;
    for (var i2 = 0; i2 < result.length; i2++) {
        if (result[i2] == name) {
            continue loop1;
        }
    }
    result.push(name);
}

A diferença de desempenho usando o Safari e Firefox é incrível, e parece que o Chrome faz o melhor trabalho de otimização.

Não sei exatamente por que os trechos acima são tão rápidos em comparação com os outros, talvez alguém mais sábio que eu tenha uma resposta. ;-)


9

usando lodash

var array = [
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
];
_.chain(array).pluck('age').unique().value();
> [17, 35]

2
Você pode explicar como fazer isso com javascript simples, como está implícito na pergunta?
Ruskin

é uma função sublinhada _.chain
vini

2
mas pluck () não está no lodash.
Yash Vekaria

11
_.chain (array) .map ('idade'). unique (). value (); trabalhou para mim.
Yash Vekaria

versão 4.0 teve algumas alterações significativas referem - stackoverflow.com/a/31740263/4050261
Adarsh Madrecha

7

Usando o Lodash

var array = [
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
];

_.chain(array).map('age').unique().value();

Retorna [17,35]


6
function get_unique_values_from_array_object(array,property){
    var unique = {};
    var distinct = [];
    for( var i in array ){
       if( typeof(unique[array[i][property]]) == "undefined"){
          distinct.push(array[i]);
       }
       unique[array[i][property]] = 0;
    }
    return distinct;
}


5

Aqui está uma solução versátil que usa reduzir, permite mapear e mantém a ordem de inserção.

itens : uma matriz

mapeador : uma função unária que mapeia o item para os critérios ou vazia para mapear o próprio item.

function distinct(items, mapper) {
    if (!mapper) mapper = (item)=>item;
    return items.map(mapper).reduce((acc, item) => {
        if (acc.indexOf(item) === -1) acc.push(item);
        return acc;
    }, []);
}

Uso

const distinctLastNames = distinct(items, (item)=>item.lastName);
const distinctItems = distinct(items);

Você pode adicionar isso ao seu protótipo Array e deixar de fora o parâmetro items se esse for o seu estilo ...

const distinctLastNames = items.distinct( (item)=>item.lastName) ) ;
const distinctItems = items.distinct() ;

Você também pode usar um conjunto em vez de uma matriz para acelerar a correspondência.

function distinct(items, mapper) {
    if (!mapper) mapper = (item)=>item;
    return items.map(mapper).reduce((acc, item) => {
        acc.add(item);
        return acc;
    }, new Set());
}

5

const x = [
  {"id":"93","name":"CVAM_NGP_KW"},
  {"id":"94","name":"CVAM_NGP_PB"},
  {"id":"93","name":"CVAM_NGP_KW"},
  {"id":"94","name":"CVAM_NGP_PB"}
].reduce(
  (accumulator, current) => accumulator.some(x => x.id === current.id)? accumulator: [...accumulator, current ], []
)

console.log(x)

/* output 
[ 
  { id: '93', name: 'CVAM_NGP_KW' },
  { id: '94', name: 'CVAM_NGP_PB' } 
]
*/


2
isso se parece com O (n ^ 2)
cegprakash 5/09/19

4

Acabei de encontrar isso e achei útil

_.map(_.indexBy(records, '_id'), function(obj){return obj})

Novamente, usando sublinhado , se você tiver um objeto como este

var records = [{_id:1,name:'one', _id:2,name:'two', _id:1,name:'one'}]

ele fornecerá apenas os objetos exclusivos.

O que acontece aqui é que indexByretorna um mapa como este

{ 1:{_id:1,name:'one'}, 2:{_id:2,name:'two'} }

e apenas por ser um mapa, todas as chaves são únicas.

Então, estou apenas mapeando essa lista de volta para a matriz.

Caso você precise apenas dos valores distintos

_.map(_.indexBy(records, '_id'), function(obj,key){return key})

Lembre-se de que o valor keyé retornado como uma sequência; portanto, se você precisar de números inteiros, deve fazer

_.map(_.indexBy(records, '_id'), function(obj,key){return parseInt(key)})

4

Eu acho que você está procurando a função groupBy (usando Lodash)

_personsList = [{"name":"Joe", "age":17}, 
                {"name":"Bob", "age":17}, 
                {"name":"Carl", "age": 35}];
_uniqAgeList = _.groupBy(_personsList,"age");
_uniqAges = Object.keys(_uniqAgeList);

produz resultado:

17,35

Demonstração do jsFiddle: http://jsfiddle.net/4J2SX/201/


3

Se, como eu, você preferir uma funcionalidade mais "funcional" sem comprometer a velocidade, este exemplo usa a pesquisa rápida de dicionário dentro do fechamento de redução.

var array = 
[
    {"name":"Joe", "age":17}, 
    {"name":"Bob", "age":17}, 
    {"name":"Carl", "age": 35}
]
var uniqueAges = array.reduce((p,c,i,a) => {
    if(!p[0][c.age]) {
        p[1].push(p[0][c.age] = c.age);
    }
    if(i<a.length-1) {
        return p
    } else {
        return p[1]
    }
}, [{},[]])

De acordo com este teste, minha solução é duas vezes mais rápida que a resposta proposta


3
[...new Set([
    { "name": "Joe", "age": 17 },
    { "name": "Bob", "age": 17 },
    { "name": "Carl", "age": 35 }
  ].map(({ age }) => age))]

3

Eu sei que meu código tem pouca duração e pouca complexidade de tempo, mas é compreensível, então tentei dessa maneira.

Estou tentando desenvolver uma função baseada em protótipo aqui e o código também muda.

Aqui, Distinct é minha própria função de protótipo.

<script>
  var array = [{
      "name": "Joe",
      "age": 17
    },
    {
      "name": "Bob",
      "age": 17
    },
    {
      "name": "Carl",
      "age": 35
    }
  ]

  Array.prototype.Distinct = () => {
    var output = [];
    for (let i = 0; i < array.length; i++) {
      let flag = true;
      for (let j = 0; j < output.length; j++) {
        if (array[i].age == output[j]) {
          flag = false;
          break;
        }
      }
      if (flag)
        output.push(array[i].age);
    }
    return output;
  }
  //Distinct is my own function
  console.log(array.Distinct());
</script>


2

Se você tiver Array.prototype.includes ou estiver disposto a preenchê- lo, isso funcionará:

var ages = []; array.forEach(function(x) { if (!ages.includes(x.age)) ages.push(x.age); });

1

Meu código abaixo mostrará a matriz única de idades, bem como a nova matriz que não possui idade duplicada

var data = [
  {"name": "Joe", "age": 17}, 
  {"name": "Bob", "age": 17}, 
  {"name": "Carl", "age": 35}
];

var unique = [];
var tempArr = [];
data.forEach((value, index) => {
    if (unique.indexOf(value.age) === -1) {
        unique.push(value.age);
    } else {
        tempArr.push(index);    
    }
});
tempArr.reverse();
tempArr.forEach(ele => {
    data.splice(ele, 1);
});
console.log('Unique Ages', unique);
console.log('Unique Array', data);```

1

Eu escrevi o meu próprio em TypeScript, para um caso genérico, como o de Kotlin Array.distinctBy {}...

function distinctBy<T, U extends string | number>(array: T[], mapFn: (el: T) => U) {
  const uniqueKeys = new Set(array.map(mapFn));
  return array.filter((el) => uniqueKeys.has(mapFn(el)));
}

Onde Ué lavável, é claro. Para objetos, você pode precisar de https://www.npmjs.com/package/es6-json-stable-stringify


1

Caso você precise de um objeto inteiro

const _ = require('lodash');

var objects = [
  { 'x': 1, 'y': 2 },
  { 'y': 1, 'x': 2 },
  { 'x': 2, 'y': 1 },
  { 'x': 1, 'y': 2 }
];

_.uniqWith(objects, _.isEqual);

[Objeto {x: 1, y: 2}, Objeto {x: 2, y: 1}]


downvoter: Mente explicando por que o voto negativo?
Cegprakash 19/11/19

1

Responder a essa pergunta antiga é inútil, mas há uma resposta simples que fala da natureza do Javascript. Objetos em Javascript são inerentemente tabelas de hash. Podemos usar isso para obter um hash de chaves exclusivas:

var o = {}; array.map(function(v){ o[v.age] = 1; });

Em seguida, podemos reduzir o hash para uma matriz de valores exclusivos:

var a2 = []; for (k in o){ a2.push(k); }

Isso é tudo o que você precisa. A matriz a2 contém apenas as idades únicas.


1

Uma linha simples com ótimo desempenho. 6% mais rápido que as soluções ES6 nos meus testes .

var ages = array.map(function(o){return o.age}).filter(function(v,i,a) {
    return a.indexOf(v)===i
});

@ Jeb50 Gostaria de adicionar uma linha múltipla que seja fácil de ler? Olhando para os outros aqui, eu realmente não sinto que eles sejam fáceis de ler ou entender. Eu acho que é melhor colocar isso em uma função que descreve o que faz.
Craig

2
Com funções de seta: array.map( o => o.age).filter( (v,i,a) => a.indexOf(v)===i). Eu uso a palavra-chave função tão raramente agora que eu tenho que ler coisas duas vezes quando eu vejo isso 😊
Drenai
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.