var db = new MatriModel();
string s = txtKeyWord.Text;
string[] words = s.Split(',');
int count = words.Length;
if (count <= 5)
{
SerachByKeyWordPanel.Visible = true;
var KeyWord = db.tblProfiles.Where(x => words.Contains(x.tblCaste.Caste) && words.Contains(x.tblCountry.Country) && words.Contains(x.City) && words.Contains(x.tblOccupation.Occupation) && words.Contains(x.tblMotherTongue.MotherTongue)).Select(x => new
{
ProfileID = x.ProfileID,
ProfileFor = x.tblProfileFor.ProfileFor,
}.ToList();
By Above code I can get details for multiple keywords but at the same time, I want to get records by single keyword also.
Please some one help me, Thanks in Advance
See the following code snippet based on a simplified object:
class MatrixModel {
public string ProfileId {get; set;}
public string Caste {get; set;}
public string Country {get; set;}
public string City {get; set;}
public string Occupation {get; set;}
public string MotherTongue {get; set;}
}
public static void Main()
{
var db = new MatrixModel[]{
new MatrixModel {
ProfileId = "1",
Caste = "Caste1",
Country = "USA",
City = "Miami",
Occupation = "System administrator",
MotherTongue = "English"
},
new MatrixModel {
ProfileId = "2",
Caste = "Caste1",
Country = "India",
City = "Mumbai",
Occupation = "developer",
MotherTongue = "English"
},
new MatrixModel {
ProfileId = "3",
Caste = "Caste1",
Country = "England",
City = "London",
Occupation = "developer",
MotherTongue = "English"
},
};
string s = "Caste1, England";
string[] words = s.Split(',');
int count = words.Length;
if (count <= 5)
{
IEnumerable<MatrixModel> KeyWord = db;
foreach(var par in words)
{
var parTrimmed = par.Trim();
KeyWord = KeyWord
.Where(x => x.Caste == parTrimmed
|| x.Country == parTrimmed
|| x.City == parTrimmed
|| x.Occupation == parTrimmed
|| x.MotherTongue == parTrimmed);
}
var result = KeyWord.Select(x => new
{
ProfileID = x.ProfileId,
}).ToList();
foreach(var item in result){
Console.WriteLine(item);
}
}
}
The result is the following:
{ ProfileID = 3 }
Related
I have a flat object, and it looks like as below
public class Test
{
public string Name {get; set;}
public string Number {get; set;}
public string Description {get; set;}
public string Name1 {get; set;}
public string Name2 {get; set;}
}
and I have the data looks like as below
List<Test> tests = new List<Test>
{
new Test{ Name = "nameA", Number=8, Description="description", Name1 = "test 1", Name2="test name1" },
new Test{ Name = "nameB", Number=3, Description="description2", Name1 = "test 2", Name2="test name2" },
new Test{ Name = "nameC", Number=4, Description="description3", Name1 = "test 3", Name2="test name3" },
};
and I am trying to form an object list that looks like below
I am using the below logic to form a list object but failed to add all objects to that,
List<dynamic> testList = new();
int rowIndex = 1;
foreach (var testDt in tests)
{
dynamic testData = new ExpandoObject();
if (rowIndex % 2 != 0)
{
testData.Name = testDt.Name;
testData.Description = testDt.Description;
testData.Number = testDt.Number;
}
else
{
testData.Name1 = testDt.Name1;
testData.Name2 = testDt.Name2;
}
testList.Add(testData);
rowIndex++;
}
But this logic is not adding all items to the list if the list has more items and could anyone please let me know where I am wrong with the above code.
Many thanks in advance!!!
Here you go:
List<Test> tests = new List<Test>
{
new Test{ Name = "nameA", Number = 8, Description = "description", Name1 = "test 1", Name2 = "test name1" },
new Test{ Name = "nameB", Number = 3, Description = "description2", Name1 = "test 2", Name2 = "test name2" },
new Test{ Name = "nameC", Number = 4, Description = "description3", Name1 = "test 3", Name2 = "test name3" },
};
var results =
from t in tests
from r in new []
{
new { t.Name, Number = t.Number.ToString(), t.Description, Name1 = "", Name2 = "", },
new { Name = "", Number = "", Description = "", Name1 = t.Name1, t.Name2, },
}
select r;
That gives me:
To use a regular foreach loop this would work:
public class Output
{
public string Name { get; set; }
public string Number { get; set; }
public string Description { get; set; }
public string Name1 { get; set; }
public string Name2 { get; set; }
}
var results = new List<Output>();
foreach (var t in tests)
{
results.Add(new Output() { Name = t.Name, Number = t.Number.ToString(), Description = t.Description, Name1 = "", Name2 = "", });
results.Add(new Output() { Name = "", Number = "", Description = "", Name1 = t.Name1, Name2 = t.Name2, });
}
I've created a new class rather than use dynamic, as dynamic generally creates more problems than it solves, IMO. I avoid it where possible.
And finally, the equivalent using LINQ's method syntax:
results =
tests
.SelectMany(t => new []
{
new Output() { Name = t.Name, Number = t.Number.ToString(), Description = t.Description, Name1 = "", Name2 = "", },
new Output() { Name = "", Number = "", Description = "", Name1 = t.Name1, Name2 = t.Name2, },
})
.ToList();
The problem is that you are adding only 1 item to the list for each iterate, however, what you need is to add 2 instead to be able to get the expected result.
You can simply do that as follows.
foreach (var testDt in tests)
{
dynamic testData1 = new ExpandoObject();
testData1.Name = testDt.Name;
testData1.Description = testDt.Description;
testData1.Number = testDt.Number;
testList.Add(testData1);
dynamic testData2 = new ExpandoObject();
testData2.Name1 = testDt.Name1;
testData2.Name2 = testDt.Name2;
testList.Add(testData2);
}
I am trying to check if more than 2 properties in a object has value and return invalid string if so
Example :
Class Student
{
string Name
string Code
string SNumber
}
Considering above code example , below scenarios can be written
if(studentObj.Name != null && studentObj.Code != null)
return "invalid";
if(studentObj.Name != null && studentObj.SNumber != null)
return "invalid";
if(studentObj.Code != null && studentObj.SNumber != null)
return "invalid";
Is there a way this can be simplified?
Thanks
typeof(Student).GetFields() // use GetProperties() if you have them, and not fields
.Select(field => field.GetValue(studentObj) as string)
.Count(value => !string.IsNullOrEmpty(value))
You could actually count:
class Student
{
public string Name {get; set;}
public string Code {get; set;}
public string SNumber {get; set;}
}
class StudentValidator
{
public string Validate(Student student)
{
int nonZeroCount = 0;
if( student.Name is object ) nonZeroCount++;
// in C# 9: if( student.Name is not null )
if( student.Code is object ) nonZeroCount++;
if( student.SNumber is object ) nonZeroCount++;
return (nonZeroCount > 2)? "invalid" : "valid";
}
}
Mind that you might prefer to check either with
string.IsNullOrEmtpty(string) or
string.IsNullOrWhitespace(string)
Here you can optionally optimize the select statement, but as an example, I offer this option for discussion:
class Program
{
static void Main(string[] args)
{
var students = new List<Student>
{
new Student{Name = "Mary", Code = "1", SNumber = "001" },
new Student{Name = "Sarah", Code = "", SNumber = "002" },
new Student{Name = "", Code = "3", SNumber = "003" },
new Student{Name = "Katherine", Code = "4", SNumber = "004" },
new Student{Name = "Eva", Code = "", SNumber = "" }
};
var listedProperty = from student in students
select new List<string> { student.Name, student.Code, student.SNumber };
listedProperty
.ToList()
.ForEach(l =>
{
var nullPropertyCount = l.Count(i => string.IsNullOrWhiteSpace(i));
if (nullPropertyCount <= 1)
{
Console.WriteLine(string.Join(", ", l.ToArray()));
}
});
Console.ReadLine();
}
}
Output result to the console:
In my application multiple reports are needed on some table, many of the fields are common in most reports, as a sample:
public class ReportStudent
{
public int Id {get; set;}
public string Name {get; set;}
public string Family {get; set;}
public DateTime BirthDate {get; set;}
public DateTime RegisterDate {get; set;}
public Double Average {get; set;}
public string FatherName {get; set;}
public string MotherName {get; set;}
}
var list1 = context.Students.Select(e=> new ReportStudent
{
Id = e.Id
Name = e.Name
Family = e.Family
BirthDate = e.BirthDate
RegisterDate = e.RegisterDate
FatherName = e.FatherName
MotherName = e.MotherName
}).ToList();
var list2 = context.Students.Select(e=> new ReportStudent
{
Id = e.Id
Name = e.Name
Family = e.Family
BirthDate = e.BirthDate
RegisterDate = e.RegisterDate
Average = e.Average
}).ToList();
How can I write this map only once? These fields are common in list1 and list2.
Id = e.Id
Name = e.Name
Family = e.Family
BirthDate = e.BirthDate
RegisterDate = e.RegisterDate
First, define an expression that will contain your common projection needs:
Expression<Func<ReportStudent, ReportStudent>> commonProjection = e => new ReportStudent
{
Id = e.Id,
Name = e.Name,
Family = e.Family,
BirthDate = e.BirthDate,
RegisterDate = e.RegisterDate,
};
Then have a method that will modify this expression to reflect the additional bindings:
public static Expression<Func<ReportStudent, ReportStudent>> MergeBindings(Expression<Func<ReportStudent, ReportStudent>> expr, Expression<Func<ReportStudent, ReportStudent>> newExpr)
{
var reportStudentType = typeof(ReportStudent);
var eParameter = expr.Parameters.First();
var eNew = Expression.New(reportStudentType);
var memberInitExpr = expr.Body as MemberInitExpression;
var memberInitNewExpr = newExpr.Body as MemberInitExpression;
var allBindings = memberInitExpr.Bindings.Concat(memberInitNewExpr.Bindings.Select(x =>
Expression.Bind(x.Member, Expression.Property(eParameter, x.Member as PropertyInfo)
)));
var eInit = Expression.MemberInit(eNew, allBindings);
var lambda = Expression.Lambda<Func<ReportStudent, ReportStudent>>(eInit, eParameter);
return lambda;
}
Usage:
var withParentsExpr = MergeBindings(commonProjection, e => new ReportStudent
{
FatherName = e.FatherName,
MotherName = e.MotherName
});
var list1 = context.Students.Select(withParentsExpr).ToList();
var withAverageExpr = MergeBindings(commonProjection, e => new ReportStudent
{
Average = e.Average
});
var list2 = context.Students.Select(withAverageExpr).ToList();
(With some help from #Nicholas Butler great answer)
If you don't want to write maps every time, you can use great library http://automapper.org/
With this library, you can define map and it automatically map all properties
You could create a function for that let say you have
public StudentReport ParseStudentReport(Student e)
{
return new StutentReport{
Id = e.Id
Name = e.Name
Family = e.Family
BirthDate = e.BirthDate
RegisterDate = e.RegisterDate
}
}
Then use it within your select statement
var list2 = context.Students.Select(ParseStudentReport);
Then add remaining properties or you could use AutoMapper, which can be found on github or as a nuget package.
I want to swap the list as explained below. I want to retain the count of list with some element values(not all) to be swapped from 'primary' to 'secondary'.
namespace listswap
{
public class emp
{
public int id { get; set; }
public string primary { get; set; }
public string fName { get; set; }
public string lName { get; set; }
public string state { get; set; }
public string country { get; set; }
}
class Program
{
static void Main(string[] args)
{
var empList = new List<emp>();
empList.AddRange(new emp[] { new emp {primary = "Yes", id = 1, fName = "Vivek", lName = "Ranjan", state = "TN", country = "India"},
new emp { primary = "No", id = 2, fName = "Deepak", lName = "Kumar", state = "AP", country = "UK"},
});
/* Desired list :
No of list 1 with two elements
empList[0]. primary = "Yes", id = 1, fName = "Vivek", lName = "Ranjan", state = "TN", country = "India"
empList[1]. primary = "No", id = 2, fName = "Vivek", lName = "Ranjan", state = "TN", country = "India"
*/
}
}
}
This is basics and as simple as:
var l1 = empList.Where(c=>c.primary == "Yes").ToList();
var l2 = empList.Where(c=>c.primary == "No").ToList();
For list of lists:
var result = empList.GroupBy(c => c.primary).Select(c => c.ToList()).ToList();
EDIT:
var primary = empList.FirstOrDefault(c => c.primary == "Yes");
var r = empList.Select(c => new emp
{
primary = c.primary,
id = c.id,
fName = primary != null ? primary.fName : c.fName,
lName = primary != null ? primary.lName : c.lName,
state = primary != null ? primary.state : c.state,
country = primary != null ? primary.country : c.country
}).ToList();
I have the following:
public class Address{
public string Number { get; set; }
public string Street { get; set; }
public string Suburb { get; set; }
}
List<Address> MyAddressList = new List<Address>();
Address MyAddress = new Address();
myAddress.Number = "5"
myAddress.Street = "Smith St"
myAddress.Suburb = "Smithsville"
MyAddressList.Add(MyAddress);
Address MyAddress2 = new Address();
myAddress2.Number = "10"
myAddress2.Street = "John St"
myAddress2.Suburb = "Johnsville"
MyAddressList.Add(MyAddress2);
string [] StreetToFind = new string {"Smith St"};
string [] SuburbToFind = new string {"Smithsville"};
string [] secondSuburbToFind = new string {"Johnsville"};
I want to search through this list and look for a combination of values and return a bool if the combination is found.
To start, I can search for an individual value in the Street Property:
bool StreetIsFound = MyAddressList.Select(x => x.Street).Intersect(StreetToFind).Any();
and the same for Suburb:
bool SuburbIsFind = = MyAddressList.Select(x => x.Suburb).Intersect(SuburbToFind).Any();
but I want to be able to search for both in a combination (bool StreetandSuburbFound)
so that if I searched for StreetToFind and SuburbToFind, StreetandSuburbFound would be true but would be false if searching for StreetToFind and secondSuburbToFind.
You can do this all with one call to Any. Like this
var isFound = MyAddressList.Any(x => StreetToFind.Contains(x.Street) && SuburbToFind.Contains(x.Suburb));
Or in query syntax
var isFound =
(from x in MyAddressList
where StreetToFind.Contains(x.Street)
&& SuburbToFind.Contains(x.Suburb)
select x)
.Any();
Or the method chain version of p.s.w.g's code:
MyAddressList.Any(x => StreetToFind.Contains(x.Street)
&& SuburbToFind.Contains(x.Suburb))
(obviously tweak as neccessary with the Contains etc)