Error when trying to List.Sort(); - c#

I have this method that creates and returns a list of strings and then should sort the strings alphabetically. I get an error (Cannot implicitly convert type void to System.Collections.Generic.List<string>) when I try this code:
public static List<string> ReturnListofFirstandLastName()
{
List<string> names = new List<string>();
Reademployeelist();
for (int i =0; i < employeelist.Count;i++)
{
names.Add(employeelist[i].first_name + " " + employeelist[i].last_name);
}
return names.Sort();
}

The problem here is that Sort will simply sort the IEnumerable, but it does not return anything (which is different than OrderBy(), which returns a new IEnumerable).
The easiest way to solve this would be to just call Sort on the list, and then return it:
// Previous code omitted
names.Sort();
return names;
}
As a side note, you might want to consider renaming some of your objects. For starters, property names are typically PascalCase (not words separated by underscores). So your employee class wouldn't have a first_name, but instead FirstName.
For example:
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Also, your employeelist can just be called employees (typically collection types are simply named the plural of what the contained type represents), and Reademployeelist might be better named something like PopulateEmployees (reading implies that it reads the list, but since you call this before iterating over the list it appears that it's actually populating the list)?
private static List<Employee> employees = new List<Employee>();
private static void PopulateEmployees()
{
employees = new List<Employee>
{
new Employee {FirstName = "Warren", LastName = "Buffett"},
new Employee {FirstName = "Jeff", LastName = "Bezos"},
new Employee {FirstName = "Larry", LastName = "Page"},
new Employee {FirstName = "Mark", LastName = "Zuckerberg"},
new Employee {FirstName = "Elon", LastName = "Musk"},
new Employee {FirstName = "Steve", LastName = "Jobs"},
new Employee {FirstName = "Oprah", LastName = "Winfrey"},
new Employee {FirstName = "Howard", LastName = "Schultz"},
new Employee {FirstName = "Larry", LastName = "Ellison"},
new Employee {FirstName = "Satya", LastName = "Nadella"},
};
}
And your method could be named GetEmployeeFirstAndLastNames, and could be simplified a little if we use some System.Linq methods like Select (to select the concatenation of first and last name from each employee), and OrderBy (which will implicitly create a new list instead of us having to do it, and we can return it's result):
public static List<string> GetEmployeeFirstAndLastNames()
{
PopulateEmployees();
return employees.Select(e => e.FirstName + " " + e.LastName)
.OrderBy(name => name)
.ToList();
}
Usage example:
private static void Main()
{
foreach (string name in GetEmployeeFirstAndLastNames())
{
Console.WriteLine(name);
}
GetKeyFromUser("\nDone! Press any key to exit...");
}
Output

Related

Filter a list of objects based on a parameter

class Officer
{
Person person;
}
class Person
{
string name;
}
Suppose I've a list of Officer and a list of Person. I want to filter these two list based on some criteria.
So I wrote this method:
public List<Person> filterName(List<Person> list)
{
// some filter logic
}
And I'm using this method for the two lists in the following way:
main()
{
...
List<Officer> officers = Initialize();
List<Person> validNames= filterNames(officers.Select(o=>o.person.name).ToList())
foreach (var officer in officers)
{
if (!validNames.Contains(officer.Person.name))
officers.remove(officer);
}
// finally I have a valid set of officers here
List<Person> persons = Initialize();
var filteredPersons = filterNames(persons.Select(o=>o.name).ToList())
}
Is there a good way to use generics so I can avoid the following code in the main method()?
List<string> validNames = filterNames(officers.Select(o=>o.fullName).ToList())
foreach (var officer in officers)
{
if (!validNames.Contains(officer.name))
officers.remove(officer);
}
And use generics somehow to update the officers list using generics.
New answer based on recent edits:
var officers = new List<Officer>
{
new Officer { Name = "Officer Foo" },
new Officer { Name = "Officer Bar" }
};
officers.RemoveAll(o => o.Name.Contains("Bar"));
// Officers now only contains "Officer Foo"
------------ Old answer here ----------------
Can you use OOP here and derive Person and Officer from something in common?
If so, then you can easily take their common property and filter on that instead of writing two separate pieces of logic to deal with each of them.
static void Main(string[] args)
{
var officers = new List<Officer>
{
new Officer { Name = "Officer Foo" },
new Officer { Name = "Officer Bar" }
};
var workers = new List<Worker>
{
new Worker { Name = "Worker Foo" },
new Worker { Name = "Worker Bar" }
};
var people = workers.Cast<IPerson>().Concat(officers);
var filteredPeople = Program.Filter(people, "Foo");
Console.ReadKey(true);
}
static IEnumerable<IPerson> Filter(IEnumerable<IPerson> people, string keyword)
{
return people.Where(p => p.Name.Contains(keyword));
}
interface IPerson
{
string Name { get; set; }
}
class Officer : IPerson
{
public string Name { get; set; }
}
class Worker : IPerson
{
public string Name { get; set; }
}
Ok, let's assume you have some complicated FilterNames function that operates on a list, and your goal is to filter out based on some Person criteria. I would rewrite the filter like this:
public bool FilterPerson(Person p)
{
//Some complicated logic
//Returns true if person should be kept
//Returns false if the person should be rejected
}
Now you can use that in a Linq statement:
var officers = Initialize().Where(o => FilterPerson(o.Person)).ToList();
No need to remove items from the list. You could still use the interim object, it just requires an additional step:
var officers = Initialize(); //Returns List<Officer>
var filteredOfficers = officers.Where(o => FilterPerson(o.Person)).ToList();

Sort a list using a search string

I am trying to sort a list on the basis of a search string. But there seems to be some issue.
Below is the code:
namespace ListDemo
{
class Program
{
static void Main(string[] args)
{
Employee e1 = new Employee {ID=1,Name="John",City="London" };
Employee e2 = new Employee { ID = 2, Name = "Mary", City = "NY" };
Employee e3 = new Employee { ID = 3, Name = "Dave", City = "Sydney" };
Employee e4 = new Employee { ID = 4, Name = "Kate", City = "Chicago" };
Employee e5 = new Employee { ID = 5, Name = "Sheela", City = "Delhi" };
List<Employee> listEmployee = new List<Employee>();
listEmployee.Add(e1);
listEmployee.Add(e2);
listEmployee.Add(e3);
listEmployee.Add(e4);
listEmployee.Add(e5);
Console.WriteLine("Enter the name via which you wana sort?");
string searchString = Console.ReadLine();
Console.WriteLine("####################Sorted List Starts##############");
var items = from element in listEmployee
orderby element.Name.Equals(searchString)
select element;
foreach (var i in items)
{
Console.WriteLine(i.Name);
}
Console.ReadLine();
}
}
class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
}
I have an Employee class with 3 public properties, ID, Name and City.
I created a list of Employees with some dummy data in it.
Now I want the user to enter a search string, which will actually be a name, and if the list contains that name, it should sort the list as according to the search string.
For ex: if a user has entered name as 'John', then the revised list should show John as first item and so on.
The code which I have written behaves abnormally.
Image is attached:
Firstly, sort by equals in descending order (it means, that it will be firt in result), and others sort by ID to save original order (or, you can use any other property for ordering):
var items = listEmployee
.OrderByDescending(e => e.Name.Equals(searchString))
.ThenBy(e => e.ID).ToArray();

Building an string from properties values of objects in a list using linq

I have a list of employees and I want to build an string with a comma separated with all LastNames from all on them.
Sample data:
Emp1.LastName = "A"
Emp2.LastName = "B"
Emp3.LastName = "C"
Dim listing As List(Of Employee)
dim flatted as string
At the end I want to get
flatted = "A,B,C"
The point is that I want to do it using linq (vb or c#)
This is how it would be done in C#. I am using a slightly different class (Person, rather than Employee), but the code will end up being the same.
// Make some experimental data...
List<Person> peeps = new List<Person>()
{
new Person() { FirstName = "Frank", LastName = "Jax" },
new Person() { FirstName = "Anne", LastName = "Wax" },
};
// This will select all of the last names from the list of people, and join them with commas.
string lastNames = string.Join(",", (from x in peeps select x.LastName));
And the class listing, for the curious.
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Something like the following should work:
List<Person> people = new List<Person>();
people.Add(new Person() { LastName = "A" });
people.Add(new Person() { LastName = "B" });
people.Add(new Person() { LastName = "C" });
var lastNames = (from person in people
select person.LastName);
var result = string.Join(",", lastNames);
Console.WriteLine(result);

C# LINQ how to flatten parent list and two nested children lists into a new list

I need to flatten a parent list and two child lists into one list. How can I do this using c# and linq?
Here is my code...
public class Customer
{
public string FirstName { get; set;}
public string LastName { get; set;}
// need to flatten these lists
public List<CreditCard> CreditCards { get; set;}
public List<Address> Addresses{ get; set;}
}
// Customer has CreditCards list and Addresses list
List<Customer> allCustomers = _db.GetAllCustomers();
// how to flatten Customer, CreditCards list, and Addresses list into one flattened record/list?
var result = allCustomers.GroupBy().SelectMany(); // how to flatten nested lists?
So the result list would contain items that look flattened like this:
Joe, Blow, Visa, Master Card, 38 Oak Street, 432 Main Avenue
Sally, Cupcake, Discover, Master Card, 29 Maple Grove, 887 Nut Street
It would flatten the customer FirstName, LastName, CreditCards list, and Addresses list.
Thanks for any feedback!
Implement IEnumerable:
public class Customer : IEnumerable<string>
{
public string FirstName {get; set;}
public string LastName {get; set;}
public List<CreditCard> CreditCards {get; set;}
public List<Address> Addresses{get; set;}
public IEnumerator<string> GetEnumerator()
{
yield return FirstName;
yield return LastName;
foreach (CreditCard c in CreditCards)
{
yield return c.ToString();
}
foreach (Address a in Addresses)
{
yield return a.ToString();
}
}
}
...
var result = allCustomers.SelectMany(c => c);
Note: this is just an example.
Use SelectMany if you want to flatten everything into one list. In this case, you are wanting a record per customer still, so you don't need to flatten.
For an array like your example, something like this should work:
var result = customers
.Select(customer => new[]
{
customer.FirstName,
customer.LastName
}
.Concat(customer.CreditCards.Select(cc => cc.ToString()))
.Concat(customer.Addresses.Select(address => address.ToString())));
Cast each type to object and then use Union to flatten them.
var allCreditCards = from customer in allCustomers
from creditCard in customer.CreditCards
select (object)creditCard;
var allAddresses = from customer in allCustomers
from address in customer.Addresses
select (object)address;
var flat = allCustomers.Concat(allCreditCards).Concat(allAddresses);
I'm not exactly sure the value in having a flattened IEnumerable<object> when the items are all different types, but that's how you'd do it.
Based on your edit, this will give you an IEnumerable<string> like you want:
var flatenned = from c in allCustomers
select
c.FirstName + ", " +
c.LastName + ", " +
String.Join(", ", c.CreditCards.Select(c2 => c2.Name).ToArray()) + ", " +
String.Join(", ", c.Addresses.Select(a => a.Street).ToArray());
Outputs:
Joe, Blow, Visa, Master Card, 38 Oak Street, 432 Main Avenue
Sally, Cupcake, Discover, Master Card, 29 Maple Grove, 887 Nut Street
Full test code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Console40
{
class LinqFlatten
{
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
// need to flatten these lists
public List<CreditCard> CreditCards { get; set; }
public List<Address> Addresses { get; set; }
}
public class CreditCard
{
public string Name { get; set; }
}
public class Address
{
public string Street { get; set; }
}
public static void Test()
{
// Customer has CreditCards list and Addresses list
List<Customer> allCustomers = GetAllCustomers();
// how to flatten Customer, CreditCards list, and Addresses list into one flattened record/list?
var flatenned = from c in allCustomers
select
c.FirstName + ", " +
c.LastName + ", " +
String.Join(", ", c.CreditCards.Select(c2 => c2.Name).ToArray()) + ", " +
String.Join(", ", c.Addresses.Select(a => a.Street).ToArray());
flatenned.ToList().ForEach(Console.WriteLine);
}
private static List<Customer> GetAllCustomers()
{
return new List<Customer>
{
new Customer
{
FirstName = "Joe",
LastName = "Blow",
CreditCards = new List<CreditCard>
{
new CreditCard
{
Name = "Visa"
},
new CreditCard
{
Name = "Master Card"
}
},
Addresses = new List<Address>
{
new Address
{
Street = "38 Oak Street"
},
new Address
{
Street = "432 Main Avenue"
}
}
},
new Customer
{
FirstName = "Sally",
LastName = "Cupcake",
CreditCards = new List<CreditCard>
{
new CreditCard
{
Name = "Discover"
},
new CreditCard
{
Name = "Master Card"
}
},
Addresses = new List<Address>
{
new Address
{
Street = "29 Maple Grove"
},
new Address
{
Street = "887 Nut Street"
}
}
}
};
}
}
}
This uses linq to objects, since it depends on string.Join:
allCustomers.Select(c=>
new { FirstName = c.FirstName, LastName= c.LastName,
CardsList = string.Join(",", c.CreditsCards.Select(c=> c.CardName))
AddressesList = string.Join(",", c.Addresses.Select(c=> c.Street)
}
)

convert string data array to list

i have an string data array which contains data like this
5~kiran
2~ram
1~arun
6~rohan
now a method returns an value like string [] data
public string [] names()
{
return data.Toarray()
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
List<Person> persons = new List<Person>();
string [] names = names();
now i need to copy all the data from an string array to an list
and finally bind to grid view
gridview.datasoutrce= persons
how can i do it. is there any built in method to do it
thanks in advance
prince
Something like this:
var persons = (from n in names()
let s = n.split('~')
select new Person { Name=s[1], Age=int.Parse(s[0]) }
).ToList();
var persons = names.Select(n => n.Split('~'))
.Select(a => new Person { Age=int.Parse(a[0]), Name=a[1] })
.ToList();
Assuming that the source data are completely valid (i.e. no negative ages, names do not contain '~', every line has both age and name, and so on), here's a very easy implementation:
List<Person> persons = new List<Person>;
foreach (var s in names()) {
var split = s.Split('~');
int age = int.Parse (split[0]);
string name = split[1];
var p = new Person() { Age = age, Name = name };
persons.Add (p);
}
You can also use a Linq query, which is shorter. See Marcelo's Answer for an example.

Categories

Resources