Filter List entries - c#

I have a list with 3 entries -
public class entry
{
string name;
string age;
string likes;
}
List<entry> groupEntry = new List<entry>();
Where -
groupEntry[0].name = "john";
groupEntry[0].age= "26";
groupEntry[0].likes= "cats";
groupEntry[1].name = "john";
groupEntry[1].age= "26";
groupEntry[1].likes= "dogs";
groupEntry[2].name = "matt";
groupEntry[2].age= "32";
groupEntry[2].likes= "frogs";
What i am trying to do is make a new list, whereby name is a unique identifier, and just create one entry per name however add the likes together into on string array with the resulting list looking like -
public class filteredEntry
{
string name;
string age;
List<string> likes;
}
List<filteredEntry> filteredGroupEntry = new List<filteredEntry>();
filteredGroupEntry [0].name = "john";
filteredGroupEntry [0].age= "26";
filteredGroupEntry [0].likes= ["cats", "dogs"];
filteredGroupEntry [1].name = "matt";
filteredGroupEntry [1].age= "32";
filteredGroupEntry [1].likes= "frogs";
My thoughts were to do a foreach with groupEntry and each time entry[i].name changes make a new record in filteredGroupEntry however could not get this to work with a new array for likes. How can I achieve this?

First of all, you need to make the fields in your entry class public. Until now your code won't compile.
Second is that likes is already a string so you cannot transform it into an array, but what you could do is just to concatenate all the stuff that a person likes and separate them with a ,. So you would group by name and take all likes values in one string. This code takes only the first age value (assuming that it is always the same John with the same age May be not the smartest solution.
List<entry> filteredList = groupEntry.GroupBy(x => x.name)
.Select(x => new entry
{
name = x.First().name,
age = x.First().age,
likes = String.Join(", ", x.Select(l=>l.likes))
}).ToList();
Later on when you want to separate the like thingies again you could split by , like this:
string [] allOneLikes = filteredList[0].likes.Split(',');
EDIT:
I just saw that you edited your post and added the filteredEntry class.
This changes the situation of course. So you could then use this class in the Select statement:
List<filteredEntry> filteredList = groupEntry.GroupBy(x => x.name)
.Select(x => new filteredEntry
{
name = x.First().name,
age = x.First().age,
likes = x.Select(l=>l.likes).ToList()
}).ToList();

I suggest grouping by via Linq:
List<filteredEntry> filteredGroupEntry = groupEntry
.GroupBy(entry => new { // grouping by name + age
name = entry.name,
age = entry.age})
.Select(chunk => new filteredEntry() {
name = chunk.Key.name,
age = chunk.Key.age,
// collapse all likes into list
likes = chunk.Select(entry => entry.likes).ToList()})
.ToList();

Related

Swap Attribute in each item in a list c#

I have a list with items as follows:
public class Student {
public string Name;
public string Nickname;
}
var students = new List<Student> { new Student {Name = "Becca", Nickname = "Rebecca"},
new Student {Name = "Ray", Nickname = "Raymond"}}
If I want to swap Name and Nickname so that students would now be
var students = new List<Student> { new Student {Name = "Rebecca", Nickname = "Becca"},
new Student {Name = "Raymond", Nickname = "Ray"}}
How do I do that in linq?
You can use Linq's Select method to create a new instance of student with the values swapped.
var students = new List<Student>
{
new Student {Name = "Becca", Nickname = "Rebecca"},
new Student {Name = "Ray", Nickname = "Raymond"}
}
var swapped = students.Select(x => new Student {Name = x.Nickname, Nickname = x.Name});
Whenever we ask how to do X with each item in a list, the answer is usually two things: How to do X, and how to do something with each item in a list. Once we see that, we can separate the two problems and start with how to do X. The second part, how to do anything with each item in a list, is much simpler.
In this case, how do we do X - create a new Student from an existing one, with the names swapped?
That could be a method like this:
Student SwapNames(Student student)
{
return new Student {Name = student.Nickname, Nickname = student.Name};
}
or simplified as
Student SwapNames(Student student) =>
new Student {Name = student.Nickname, Nickname = student.Name};
Having solved that, determining how to do it to to items in a list is easier.
var swappedStudents = new List<Student>();
foreach(var student in originalStudents)
{
swappedStudents.Add(SwapNames(student));
}
Or, using LINQ:
var swappedStudents = originalStudents.Select(student => SwapNames(student));
...or simplified:
var swappedStudents = originalStudents.Select(SwapNames);
These both produce an IEnumerable<Student>. If we wanted a List<Student> we could append:
var swappedStudents = originalStudents.Select(SwapNames).ToList();
In the examples so far, the method that does X - in this case, swapping the names, is in a separate function. That can be helpful for readability. But we can also do it inline with an anonymous function, like this:
var swappedStudents = originalStudents.Select(
student => new Student { Name = student.Nickname, Nickname = student.Name });
That's an anonymous function that takes a Student as an argument and returns a new Student with the names swapped.

Combine two list data into single list C#

So i have following two list using linq.
List<One> one= A.Common
.Join(B.Common,
a => a.ID,
b=> b.ID,
(a, b) => new One
{
ID = b.PID,
Name = b.PCName,
LastName = a.LName
}).ToList();
List<One> two = (from c in D.Options
select new One
{
MainName = c.mName
}).ToList();
List<One> sn = one.Concat(two).ToList();
I am concating both list. But when i debug i am getting MainName as null in sn list.
How do i get data from both list in single list??
This is how you do it:
var sn = one.Zip(two, (x, y) => new One{
ID = x.ID,
Name = x.Name,
LastName = x.LastName,
MainName = y.MainName
});
You want the MainName property assigned for all the list values in List ONE ?
As from above code concatenation will join two list and the MainName will be not set for list one elements.
one.Concat(two)
Above line will just concat the both lists to one list elements.
You can use the LINQ Concat and ToList methods:
var mergedList = YourFirstList.Concat(YourSecondList)
.Concat(YourThirdList)
.ToList();
Edit:
one.Concat(two).Select(g => g.Aggregate((p1,p2) => new One
{
ID = p1.ID,
Name = p1.PCName,
LastName = p1.LName,
MainName = p2.mName
}));
more efficient ways to do this - the above will basically loop through all the entries, creating a dynamically sized buffer.
var mergedList = new List<One>(YourFirstList.Count +
YourSecondList.Count +
YourThirdList.Count);
mergedList.AddRange(YourFirstList);
mergedList.AddRange(YourSecondList);
mergedList.AddRange(YourThirdList);
AddRange is special-cased for ICollection<T> for efficiency.
You can use the Zip method.
one.Zip(two,(o1, o2) => new One()
{
ID = o1.ID,
Name = o1.PCName,
LastName = o1.LName,
MainName = o2.mName
});

c# get feasible values using in a string, then search in lookup, then limit search by a string

Having a lookup structure like
public class LookupEntry
{
public string Key { get; set; }
public string Value { get; set; }
}
//inside main
var list = new List<LookupEntry>(new LookupEntry[]
{
new LookupEntry() {Key="A", Value="mo" },
new LookupEntry() {Key="A", Value="nu"},
new LookupEntry() {Key="B", Value="ag"},
new LookupEntry() {Key="B", Value="bi"},
new LookupEntry() {Key="B", Value="cu"},
new LookupEntry() {Key="C", Value="tu"},
new LookupEntry() {Key="D", Value="uo"},
new LookupEntry() {Key="D", Value="vu"},
new LookupEntry() {Key="D", Value="zu"},
new LookupEntry() {Key="E", Value="ve"}
});
string original = "AD";
string large = "mobivecuvumonubinuzumozu";
// ABEBDAABADAD would be codified string
And using original string "AD" I would like to get possible codified strings
so for instance I would get (using lookup)
"mouo"
"nuuo"
"movu"
"nuvu"
"mozu"
"nuzu"
for AD string
But instead Of getting all combinations from lookup I would like To limit search with large string getting possible combinations
so in that case I would get
"nuzu"
"mozu"
I am doing something like
var lookup = list.ToLookup(x => x.Key, x => x.Value);
var allAs = lookup["A"].ToList();
var allDs = lookup["D"].ToList();
But I do not know how to continue, is it a good option to search all possibilities fisrt and then remove the ones that are not in string
You can try the following idea:
var query = allAs.SelectMany(x => allDs, (x, y) => x + y).Where(large.Contains);
This does a cartesian join on the two lists, and filters by whether the result is in the large string.
Alternatively, in LINQ query syntax, it looks like this:
var query = from x in allAs
from y in allDs
where large.Contains(x + y)
select x + y;
Output:
mozu
nuzu

Can i retrieve DISTINCT value of an array field using LINQ?

I have class object (for simplicity sake, let say, class name is Person with fields as FirstName, Lastname, YearBorn)
I get my data from DB but now want to have distinct year(s) in an array, can this be done using LINQ?
I am passing List<person> Data as a parameter to a method and want to return an array of Distinct year from data.
Any help will be appreciated.
Assuming YearBorn is a Datetime (?)
var years = data
.Select(m => m.YearBorn.Year).Distinct();
if it's an int
var years = data.Select(m => m.YearBorn).Distinct();
if it's a nullable DateTime
var years = data
.Where(m => m.YearBorn.HasValue)
.Select(m => m.YearBorn.Value.Year).Distinct();
You need to use Enumerable.Distinct Method (IEnumerable, IEqualityComparer) where like a second parameter you specify equality rule, so Distict will know which entities are considered equal so will skip them in case of more then one.
Use the Distinct standard query operator:
var years = data.Select(p => p.Year).Distinct().ToArray();
If you wish to get all of the people elements that have distinct years, then you can use DistinctBy from the morelinq library.
Bit late but :(
List<Person> persons = new List<Person>();
persons.Add(new Person() { Forename = "Onam", Surname = "Chilwan", DOB = new DateTime(1984, 8, 23) });
persons.Add(new Person() { Forename = "Onam", Surname = "Chilwan", DOB = new DateTime(1972, 8, 23) });
persons.Add(new Person() { Forename = "Onam", Surname = "Chilwan", DOB = new DateTime(1988, 8, 23) });
persons.Add(new Person() { Forename = "Onam", Surname = "Chilwan", DOB = new DateTime(1984, 8, 23) });
int[] years = persons.Select(x => x.DOB.Year).Distinct().ToArray();
public class Person
{
public string Forename;
public string Surname;
public DateTime DOB;
}

Why can't I set properties of iteration variables in a foreach loop?

string newName = "new name";
int[] numbers = new int[] { 1, 2, 3 };
var people = numbers.Select(n => new Person()
{
Name = n.ToString()
});
foreach (var person in people)
{
person.Name = newName;
}
Debug.WriteLine(people.First().Name == newName); // returns false
I expected the above line to return true. Why can't I set properties of iteration variables inside a foreach loop?
people is a query definition with deferred execution. Your foreach over the query is irrelevant, this isn't about an inability to set a property. When you invoke First(), you run the query again.
To be clear, the query definition here is that for the elements in numbers, create a new Person and assign the value of the current number element to the Person's Name property. When you iterate in the foreach loop, the query evaluates, and you create new Person objects. But those Person objects are not in the query, it's just a definition! Running the query again executes the definition again, creating different Person objects. The fact that you modified the query's original results does not impact the second set of results.
If you would like an immediate execution, use
var people = numbers.Select(n => new Person()
{
Name = n.ToString()
}).ToList();
You'll find your changes in the loop sticking, because now people is a concrete list instead of a query definition.
foreach (var person in people)
{
person.Name = newName;
}
Debug.WriteLine(people.First().Name.Equals(newName)); // returns true
This is a perfect example of deferred execution.
If you try this example it works as you expect since the ToList executes the query.
string newName = "new name";
int[] numbers = new int[] { 1, 2, 3 };
var people = numbers.Select(n => new Person()
{
Name = n.ToString()
}).ToList(); // <===== here
foreach (var person in people)
{
person.Name = newName;
}
var b = people.First().Name == newName;

Categories

Resources