Esses
dias estava no trabalho conversando com alguns colegas sobre um artigo que
citava as perguntas mais frequentes em entrevistas para analista de
sistemas/desenvolvedor/programador no Google, Microsoft, IBM, Yahoo, etc...
nas gigantes de tecnologia.
E
uma das questões era como fazer a troca de valores entre duas variáveis
numéricas sem o uso de uma variável auxiliar.
Hoje
lendo meus e-mails passei pela chamada de um novo post em um grupo que
participo no LinkedIn sobre desenvolvimento na plataforma .NET, e deste post me
inspirei a fazer este (nada se cria...) e mais ainda, a colocar uma questão em
nossa prova de seleção para analista de sistemas no estilo “não use uma
variável/coleção auxiliar”.
Pense
na classe abaixo:
1: using System;
2: using System.Text;
3: namespace com.jeanjmichel.blogspot.testyield
4: {
5: public class Person
6: {
7: private int age;
8: private char gender;
9: private String name;
10: public int Age {set; get;}
11: public char Gender
12: {
13: get { return this.gender; }
14: }
15: public String Name { set; get; }
16: public Person(int age, char gender, String name)
17: {
18: this.age = age;
19: this.gender = gender;
20: this.name = name;
21: }
22: override public String ToString()
23: {
24: StringBuilder sb = new StringBuilder();
25: sb.Append(this.name);
26: sb.Append(" ");
27: sb.Append(this.age);
28: sb.Append(" years old");
29: sb.Append(this.gender == 'M' ? " man" : " woman");
30: return sb.ToString();
31: }
32: }
33: }
Agora
vamos usar a uma classe que utiliza ela:
1: using System;
2: using System.Collections.Generic;
3: namespace com.jeanjmichel.blogspot.testyield
4: {
5: public class Program
6: {
7: private static List<Person> persons = new List<Person>();
8: static void PopulatePersonsList()
9: {
10: persons.Add(new Person(34, 'M', "Michel, Jean J."));
11: persons.Add(new Person(0, 'F', "Michel, Helena M."));
12: persons.Add(new Person(60, 'M', "Doe, John"));
13: persons.Add(new Person(47, 'F', "Doe, Jane"));
14: persons.Add(new Person(41, 'M', "Smith, John"));
15: }
16: static void Main(string[] args)
17: {
18: PopulatePersonsList();
19: foreach (Person p in persons)
20: Console.WriteLine(p);
21: Console.ReadKey();
22: }
23: }
24: }
A saída da execução da classe é:
1: Michel, Jean J. 34 years old man
2: Michel, Helena M. 0 years old woman
3: Doe, John 60 years old man
4: Doe, Jane 47 years old woman
5: Smith, John 41 years old man
Se quisermos criar um método que retorne uma lista com apenas as pessoas do sexo masculino ou feminino para fazermos algo, como exibir a lista? Claro que não podemos percorrer a lista original excluindo as pessoas do sexo oposto ao pesquisado, então a solução seria criar uma lista auxiliar?
Podemos
encurtar esse caminho executando exatamente o desejado, filtrar a lista pelo atributo gender da classe Person, porém sem declarar uma nova
lista ou alterar a lista original, dando a impressão de que estamos fazendo o desejado “sem usar uma
variável auxiliar”.
Veja
isso:
1: static IEnumerable<Person> FilterPersonsListByGender(char gender)
2: {
3: foreach (Person p in persons)
4: if (p.Gender == gender) yield return p;
5: }
O
que faz a palavra reservada yield é retornar quando a expressão for true. Da
para usar com break também e parar um laço, por exemplo. Mais detalhes direto
na fonte (MSDN): https://msdn.microsoft.com/pt-br/library/9k7k7cf0.aspx.
Assim
ficaria a classe final:
1: using System;
2: using System.Collections.Generic;
3: namespace com.jeanjmichel.blogspot.testyield
4: {
5: public class Program
6: {
7: private static List<Person> persons = new List<Person>();
8: static void PopulatePersonsList()
9: {
10: persons.Add(new Person(34, 'M', "Michel, Jean J."));
11: persons.Add(new Person(0, 'F', "Michel, Helena M."));
12: persons.Add(new Person(60, 'M', "Doe, John"));
13: persons.Add(new Person(47, 'F', "Doe, Jane"));
14: persons.Add(new Person(41, 'M', "Smith, John"));
15: }
16: static IEnumerable<Person> FilterPersonsListByGender(char gender)
17: {
18: foreach (Person p in persons)
19: if (p.Gender == gender) yield return p;
20: }
21: static void Main(string[] args)
22: {
23: PopulatePersonsList();
24: foreach(Person p in FilterPersonsListByGender('F'))
25: Console.WriteLine(p);
26: Console.ReadKey();
27: }
28: }
29: }
E
essa é a saída agora que temos:
1: Michel, Helena M. 0 years old woman
2: Doe, Jane 47 years old woman
Em
nenhum momento você verá ser criada uma nova lista :)
Achei
legal, resolvi postar, agora é elaborar uma questãozinha legal para a prova e
ver se a galera vai conhecer esse o yield ;)