Swap Attribute in each item in a list c# - 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.

Related

iteration over two lists in EF notation

I am using EF MVC.
In my model I have a User that I want to turn into a Student and I need to assign some fields to the Student. I am making a method to batch Users to Students and I need to assign some fields to the Student. This is what I am currently doing
var students = db.Students.AsQueryable();
var users = db.Users.Where(u => !students.Any(s => s.UserId == u.Id) ).ToList();//exclude current students from users
Student[] filteredStudents = new Student[users.Count];
var i = 0;
foreach (var user in users)
{
filteredStudents[i] = (Student)user;
filteredStudents[i].CreatedDate = DateTime.Now;
filteredStudents[i].ModifiedDate = DateTime.Now;
i++;
}
db.Students.AddRange(filteredStudents);
And in my Student class
public static explicit operator Student(User user)
{
Student student = new Student() { UserId = user.Id, ApplicationUser = user };
return student;
}
I feel like there should be something more elegant that I am missing.
I have seen zips but I wanted something that resembles EF notation, like this pseudo code
var finalList = students.AssignMany(UserId = Id, this.User = User, Users.Select(Id, User));
Is this possible?
By using ConvertAll() you can use your function that takes a user and returns a student and pass it as a parameter. The ConvertAll function will then return a list of Students.
var users = db.Users.Where(u => !students.Any(s => s.UserId == u.Id) ).ToList();//exclude current students from users
var newStudents = users.ConvertAll(new Converter<User, Student>(UserToStudent)); //newStudents will contain the converted users, to do with what you want.
......snip.....
function static Student UserToStudent(User toConvert){
Student student = new Student(){UserId = toConvert.Id, ApplicationUser = toConvert, CreatedDate = DateTime.Now, ModifiedDate = DateTime.Now};
return student;
}

Return full row from search

I'm new to ASP.NET MVC , I wrote C# code for search in table that search for the person name how can I store the full row to use the other information for the same person such as age, gender?
public ActionResult Index(string searching)
{
var PersonTable = db.Person;
var Name= PersonTable.Where(x => x.Name.ToLower().Contains(searching.ToLower()));
return null;
}
i try to explain with example, in my case i get the whole row by 'select s'
public void LinqTest() {
List<Student> list1 = new List<Student> {
new Student() {id=1,name="Ali Imran",age=25 },
new Student() {id=1,name="Usman Ali",age=27 },
new Student() {id=1,name="Umer Ali",age=30 },
};
var result = from s in list1 where s.age>27 select s ;
foreach (Student std in result)
{
Console.WriteLine(std.id+"-"+std.name + "-" + std.age);
}
}

List order by another contained list

I have a list of Objects and one of the item is another list. How can I Group them based on the inner list.
Here is an example of what I wish to do.
class Student
{
public string Name;
public int Age;
public List<GroupInfo> GroupList; // This is the inner list
}
class GroupInfo
{
public string GroupName;
public int GroupId;
}
static void Main()
{
GroupInfo firstGroup = new GroupInfo
{
GroupId = 1,
GroupName = "First group"
};
GroupInfo secondGroup = new GroupInfo
{
GroupId = 2,
GroupName = "Second group"
};
GroupInfo thirdGroup = new GroupInfo
{
GroupId = 3,
GroupName = "Third group"
};
GroupInfo fourthGroup = new GroupInfo
{
GroupId = 4,
GroupName = "Fourth group"
};
List<Student> studentList = new List<Student>();
Student firstStudent = new Student();
firstStudent.Name = "Name1";
firstStudent.Age = 15;
firstStudent.GroupList = new List<GroupInfo>();
firstStudent.GroupList.Add(firstGroup);
firstStudent.GroupList.Add(secondGroup);
studentList.Add(firstStudent);
Student secondStudent = new Student();
secondStudent.Name = "Name2";
secondStudent.Age = 17;
secondStudent.GroupList = new List<GroupInfo>();
secondStudent.GroupList.Add(firstGroup);
secondStudent.GroupList.Add(thirdGroup);
studentList.Add(secondStudent);
Student thirdStudent = new Student();
thirdStudent.Name = "Name3";
thirdStudent.Age = 18;
thirdStudent.GroupList = new List<GroupInfo>();
thirdStudent.GroupList.Add(secondGroup);
thirdStudent.GroupList.Add(thirdGroup);
thirdStudent.GroupList.Add(fourthGroup);
studentList.Add(thirdStudent);
List<GroupInfo> groupInfoList = new List<GroupInfo>();
// Now What I want is to get a group List Where...
foreach (var student in studentList)
{
// ...First Group Should contains firstStudent and secondStudent
// Second group Should firstStudent & thirdStudent
// Third group Should contains secondStudent & thirdStuden
// Fourth Group Should contains only thirdStudent
}
}
One way is to iterate on the whole List and populate the GroupInfo List. Just wondering is there any other way to do this task.
You can do this with SelectMany like this:-
var result = studentList.SelectMany(x => x.GroupList,
(studentObj, groups) => new { studentObj, groups })
.GroupBy(x => new { x.groups.GroupId, x.groups.GroupName })
.Select(x => new
{
GroupId = x.Key.GroupId,
GroupName = x.Key.GroupName,
Students = x.Select(z => z.studentObj).ToList()
});
Since your GroupInfo class only has two properties i.e. GroupId & GroupName, you won't be able to fetch the Students associated with it. This is the reason I am fetching anonymous type out of it.
I am getting following output with this query:-

Nested group by based on flatten record set

I have the following responses from the API. How can I group them into the following structure?
Student[]
- Name
- Classes[]
- ClassName
- ClassId
- ClassCategories[]
- CategoryName
- CategoryWeight
- Assignments[]
- AssignmentName
- Score
I was managed to group them until the "Classes" level but unable to get the ClassCategories for each of the classes
var data = (from result in results
group result by new { result.StudentId, result.FirstName, result.LastName, result.MiddleInitial }
into StudentGroup
select new GroupedStudent
{
StudentId = StudentGroup.Key.StudentId,
FullName = string.Format("{0} {1} {2}", StudentGroup.Key.FirstName, StudentGroup.Key.MiddleInitial, StudentGroup.Key.LastName).Replace(" ", " "),
Classes = from result in results
group result by new { result.ClassId, result.ClassName } into ClassGroup
select new groupedClass
{
ClassName = ClassGroup.Key.ClassName,
ClassId = ClassGroup.Key.ClassId,
ClassCategories = ...
})
}).ToList();
Can anyone please assists me? Thank you.
First, you have make ClassGroup from StudentGroup not from results.
Classes = from s in StudentGroup group result by new { s.ClassId, s.ClassName } into ClassGroup
The complete linq query is as follows:
var data =
(from result in results
group result by new { result.StudentId, result.FirstName, result.LastName, result.MiddleInitial } into StudentGroup
select new
{
StudentId = StudentGroup.Key.StudentId,
FullName = string.Format("{0} {1} {2}", StudentGroup.Key.FirstName, StudentGroup.Key.MiddleInitial, StudentGroup.Key.LastName).Replace(" ", " "),
Classes = (from s in StudentGroup
group s by new { s.ClassId, s.ClassName } into ClassGroup
select new
{
ClassId = ClassGroup.Key.ClassId,
ClassName = ClassGroup.Key.ClassName,
ClassCategories = (from c in ClassGroup
group c by new { c.CategoryName, c.CategoryWeight } into CategoryGroup
select new
{
CategoryName = CategoryGroup.Key.CategoryName,
CategoryWeight = CategoryGroup.Key.CategoryWeight,
Assignments = (from ct in CategoryGroup
group ct by new { ct.AssignmentName, ct.Score } into AssingnmentGroup
select new
{
AssignmentName = AssingnmentGroup.Key.AssignmentName,
Score = AssingnmentGroup.Key.Score
}).ToList()
}).ToList()
}).ToList()
}).ToList();
For example, if you want to access to the first Assignment's score, you can get it like this:
var student = data.FirstOrDefault();
var score = student.Classes[0].ClassCategories[0].Assignments[0].Score;
This is usually how I do It.
Create a class to store your data
Create a list of that class type
In your case instead of string dataRow maybe you can use a sub class
.
// get data from webservice
var json = webClient.DownloadString(url);
var values = JsonConvert.DeserializeObject<JArray>(json);
// create a list to save all the element
List<myClass> classList = new List<myClass>();
// process every row
foreach (string dataRow in values)
{
string[] dataField = dataRow.Split(',');
// have a constructor to assign each value to this element
myClass ctROW = new myClass(dataField);
classList.add(ctROW );

Concat Two IQueryables with Anonymous Types?

I've been wrestling with this a little while and it's starting to look like it may not be possible.
I want to Concat() two IQueryables and then execute the result as a single query. I tried something like this:
var query = from x in ...
select new
{
A = ...
B = ...
C = ...
};
var query2 = from y in ...
select new
{
A = ...
B = ...
C = ...
};
var query3 = query.Concat(query2);
However, the last line gives me the following error:
'System.Linq.IQueryable' does not contain a definition for 'Concat' and the best extension method overload 'System.Linq.ParallelEnumerable.Concat(System.Linq.ParallelQuery, System.Collections.Generic.IEnumerable)' has some invalid arguments
It appears it's expecting an IEnumerable for the argument. Is there any way around this?
It looks like I could resolve both queries to IEnumerables and then Concat() them. But it would be more efficient to create a single query, and it seems like that should be possible.
As you said previously in the comments, it seems that the two queries return different objects:
Query 1 (as per comment):
f__AnonymousTypee<Leo.Domain.FileItem,Leo.Domain.Employ‌​ee,int,string,string>
Query2 is
f__AnonymousTypee<Leo.Domain.FileItem,L‌​eo.Domain.Employee,int?,string,string>
This is why Concat is giving you an error message complaining about invalid arguments.
Anonymous objects will be equivalent types to other anonymous objects with the same property names and types declared in exactly the same order.
Assuming both query and query2 from from the same contexts, you should be able to combine the two, provided they are queries of equivalent types.
Your comment indicates that neither are of the same type.
query returns objects of type Anon<FileItem, Employee, int, string, string>
query2 returns objects of type Anon<FileItem, Employee, int?, string, string>.
You cannot combine the two because they are of different types. You'll need to make sure that both queries return objects of the same type.
var query = from x in ...
select new
{
A = (FileItem)...
B = (Employee)...
C = (int)...
...
};
var query2 = from y in ...
select new
{
A = (FileItem)...
B = (Employee)...
C = (int)...
...
};
The IDE determined query and query2 are of different types, while the IEnumerable<TSource> Concat<TSource>() extension method expects two same types (IEnumerable<TSource>). The three TSource's must be the same.
string[] strA = {"123", "234", "345"};
int[] intA = { 1, 2, 3 };
var query = from s in strA
select s;
var query2 = from i in strA // intA
select i;
var query3 = query.Concat(query2);
Uncomment "// intA" in VS and you'll see the difference.
Are you missing any namespace? Normally I mark my .NET Project Properties to target .net 4.0 for vs 2010. I do not use .net 4.0 Client Profile.
Please make sure that the types of A, B and C is matches in both the query anonymous types. Also the order of A, B and C should also match in both queries.
The following example works like a charm.
namespace Test
{
using System;
using System.Collections.Generic;
using System.Linq;
internal class Employee
{
public string Name { get; set; }
public int Age { get; set; }
public double Salary { get; set; }
public string Address { get; set; }
}
internal class Program
{
private static List<Employee> employees = new List<Employee>();
private static void BuildList()
{
employees.AddRange(
new Employee[]
{
new Employee() {Name = "Tom", Age = 22, Address = "sample1", Salary = 10000},
new Employee() {Name = "Mithun", Age = 27, Address = "sample1", Salary = 20000},
new Employee() {Name = "Jasubhai", Age = 24, Address = "sample1", Salary = 12000},
new Employee() {Name = "Vinod", Age = 34, Address = "sample1", Salary = 30000},
new Employee() {Name = "Iqbal", Age = 52, Address = "sample1", Salary = 50000},
new Employee() {Name = "Gurpreet", Age = 22, Address = "sample1", Salary = 10000},
}
);
}
private static void Main(string[] args)
{
BuildList();
var query = from employee in employees
where employee.Age < 27
select new
{
A = employee.Name,
B = employee.Age,
C = employee.Salary
};
var query2 = from employee in employees
where employee.Age > 27
select new
{
A = employee.Name,
B = employee.Age,
C = employee.Salary
};
var result = query.Concat(query2);
foreach (dynamic item in result.ToArray())
{
Console.WriteLine("Name = {0}, Age = {1}, Salary = {2}", item.A, item.B, item.C);
}
}
}
}

Categories

Resources