I'm reding a .txt file that contains a list of several names in one single column, they are listed like this:
Lastname Middlename Name:
Lastname Middlename Name:
Lastname Middlename Name:
Lastname Middlename Name:
Lastname Middlename Name:
I only want to keep the initials of every name and add them to another list, for example:
Lastname Middlename Name: => LAMN
Do I have to separate by spaces? or use several removes? or use RegEX?
Thanks!
var result = File.ReadAllLines("text.txt")
.Select(line => new string (line.Split(' ')
.Select(s => s.First())
.ToArray())
).ToList();
Edit:
To get two letters from last name:
var result = File.ReadAllLines("text.txt").Select(line =>
{
var words = line.Split(' ');
var la = words.First().Take(2);
var mn = words.Skip(1).Select(s => s.First());
return new string(la.Concat(mn).ToArray()).ToUpper();
}
).ToList();
The result with be: LAMN
public List<Person> ParseFile(string filePath)
{
List<Person> lp = new List<Person>();
using (StreamReader sr = new StreamReader(filePath))
{
while (!sr.EndOfStream)
{
lp.Add(new Person(sr.ReadLine()));
}
}
return lp;
}
With
class Person
{
public Person(string fullName)
{
this.fullName = fullName;
}
private string fullName;
public string FullName
{
get { return fullName; }
set { fullName = value; }
}
private string initials;
public string Initials
{
get { return String.Join("",new string[]{
String.Join("",fullName.Split(new char[] { ' ' }).Take(1).Select(i => i.Substring(0, 2))),
String.Join("",fullName.Split(new char[] { ' ' }).Skip(1).Select(i => i.Substring(0, 1)))
});
set { initials = value; }
}
}
First I would make a Person class:
public class Person
{
string _initials = "";
public String FirstName { get; set; }
public String LastName { get; private set; }
public String MiddleName { get; private set; }
public String Initials { get { return _initials; } }
public String FullName { get { return FirstName + MiddleName + LastName; } }
public Person(String name)
{
string[] names = name.Split(' ');
if (names.Length != 3)
{
throw new ArgumentException("Incorrect format for a person.");
}
FirstName = names[2];
MiddleName= names[1];
LastName = names[0];
_initials =
String.Concat(LastName[0],LastName[1],MiddleName[0],FirstName[0]);
}
}
Then populate the Person class with the file:
List<Person> personsList = new List<Person>();
using (StreamReader reader = new StreamReader(filePath))
{
while (!reader.EndOfStream)
{
Person p = new Person(reader.ReadLine());
personsList.Add(p);
}
}
Then you can access the Person's first,last,and middle name as well as their initials:
foreach(Person p in personsList)
{
Console.WriteLine(p.Initials);
}
May be it's not a complete solution for your question, but I think is the better way to get initials without using LINQ.
Regex to extract initials from Name
Related
I am attemping to read a text file in the format of
(The # at end is just the number of classes they're in, but I dont save the course name with the fac/students class)
Course Biology
Faculty Taylor Nate 0
Student Doe John 3
Student Sean Big 0
Course Art
Faculty Leasure Dan 1
The first input should be a course, followed by the faculty and students of the specific course. The Course class should contain a collection of faculty members and a collection of students.
I have been able to put each course/student/faculty into their respective class, but I am having trouble visualizing a way to add the students/faculty to the course.
My current idea putting the data into their respective classes would be to keep the current index of the course- therefore I have it saved as
courses[currentCourse++]
so when I parse the next line, (being a faculty/student) I already know what the course index should be.
using (StreamReader reader = new StreamReader(fileName))
{
while (!reader.EndOfStream)
{
lineCounter++;
line = reader.ReadLine();
string[] words = line.Split(' ');
Console.WriteLine(words[0]);
if (words[0] == "Course")
{
string nameOfCourse = words[1];
courses[currentCourse++] = new Course
{
Name = nameOfCourse
};
}
if (words[0] == "Faculty")
{
string firstName = words[1];
string lastName = words[2];
string numOfClasses = words[3];
faculty[currentFaculty++] = new Faculty
{
FirstName = firstName,
LastName = lastName,
NumOfClasses = numOfClasses,
};
}
if (words[0] == "Student")
{
string firstName = words[1];
string lastName = words[2];
string numOfClasses = words[3];
students[currentStudent++] = new Student
{
FirstName = firstName,
LastName = lastName,
NumOfClasses = numOfClasses,
};
}
I know the problem lies in the courses class itself- but i'm not sure the terminology to add a class to another class.
public class Course
{
public override string ToString()
{
return $"{Name}";
}
public string Name { get; set; }
}
public class Student
{
public override string ToString()
{
return $"{FirstName} {LastName} {NumOfClasses}";
}
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
public string NumOfClasses { get; set; } = string.Empty;
}
Thanks for reading!
You want to add a collection of Student and Faculty to the course class, correct? You can do so like this by simply adding a List<T> to your Course class and then initializing it in a constructor.
public class Course
{
public override string ToString()
{
return $"{Name}";
}
public string Name { get; set; }
public List<Student> Students { get; set; }
public List<Faculty> FacultyMems { get; set; }
public Course()
{
Students = new List<Student>();
FacultyMems = new List<Faculty>();
}
}
And in your using block, you can add each student/faculty to the course as so:
if (words[0] == "Course")
{
string nameOfCourse = words[1];
currentCourse++;
courses[currentCourse] = new Course
{
Name = nameOfCourse
};
}
if (words[0] == "Faculty")
{
string firstName = words[1];
string lastName = words[2];
string numOfClasses = words[3];
courses[currentCourse].FacultyMems.Add(new Faculty
{
FirstName = firstName,
LastName = lastName,
NumOfClasses = numOfClasses,
});
}
if (words[0] == "Student")
{
string firstName = words[1];
string lastName = words[2];
string numOfClasses = words[3];
courses[currentCourse].Students.Add(new Student
{
FirstName = firstName,
LastName = lastName,
NumOfClasses = numOfClasses,
});
}
With this, each time you encounter "Course" your course list will add a new item and then you can append students/faculty/etc when those values occur.
This can be simplified even further but the concept is there for you to follow. Hope this helps.
If I'm understanding you correctly, you want your courses to have a list of faculty and students?
public class Course
{
public override string ToString()
{
return $"{Name}";
}
public string Name { get; set; }
public List<Student> Students { get; set; }
public List<Faculty> FacultyMembers {get; set;}
}
Just be sure to initialize the Lists before trying to add things to them otherwise you'll get a null ref exception.
I have a file upload which receives a tab delimited list that I'm trying to split into a list of employee objects using the headers as properties. I've tried splitting the list into objects by line as well as by tab, however I'm not getting the correct list of objects.
Here's an example of the tab separated list:
domainName Name accountname givenname surname email physicaldeliveryOffice
"CN=Fred Smith,OU=Sales,OU=MRO,OU=Users,OU=Owasso,OU=Test,DC=test,DC=com" Fred Smith Fred.Smith Fred Smith Fred.smith#test.com office"
"CN=John Smith,OU=Sales,OU=MRO,OU=Users,OU=Miramar,OU=test,DC=test,DC=com" John Smith John.Smith John Smith John.smith#test.com office"
What I'd like is to create a list of employees using the columns as properties..
Here's what I've tried so far:
Employee Class
public class Employee
{
public string DomainName { get; set; }
public string Name { get; set; }
public string SamAccountName { get; set; }
public string GivenName { get; set; }
public string Surname { get; set; }
public string Email { get; set; }
public string PhysicalDeliveryOfficeName { get; set; }
}
Code that reads and parses the list into objects:
FileInfo file = new FileInfo(Server.MapPath("~/MyFiles/" + fileName));
string[] delimitedByLine = System.IO.File.ReadAllText(file.FullName).Split(new string[] { "\n", "\r\n"}, StringSplitOptions.RemoveEmptyEntries);
var employeesList = delimitedByLine.Select(x => new Employee
{
DomainName = x[0].ToString(),
Name = x[1].ToString(),
AccountName = x[2].ToString(),
GivenName = x[3].ToString(),
Surname = x[4].ToString(),
Email = x[5].ToString(),
PhysicalDeliveryOfficeName = x[6].ToString()
}).ToList();
return employeesList;
Update
After some help, here's what I was able to do to get it to work:
public ActionResult Parse(string fileName)
{
try
{
FileInfo file = new FileInfo(Server.MapPath("~/MyFiles/" + fileName));
string[] delimitedByLine = System.IO.File.ReadAllText(file.FullName).Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToArray();
var employeeList = delimitedByLine.Select(x =>
{
string[] delimitedByTab = x.Split(new string[] { "\t" }, StringSplitOptions.None);
return new Employee()
{
DomainName = delimitedByTab[0].Replace("\"", ""),
Name = delimitedByTab[1],
SamAccountName = delimitedByTab[2],
GivenName = delimitedByTab[3],
Surname = delimitedByTab[4],
Email = delimitedByTab[5],
PhysicalDeliveryOfficeName = delimitedByTab[6]
};
}).ToList();
return PartialView("~/Views/Shared/_Employees", employeeList);
}
catch (Exception ex)
{
throw ex;
}
}
You need to split the string in each line.
var employeeList = delimitedByLine.Select(x=>
{
string[] delimitedByComma = x.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
return new Employee()
{
DomainName = delimitedByComma[0],
Name = delimitedByComma[1],
AccountName = delimitedByComma[2],
GivenName = delimitedByComma[3],
Surname = delimitedByComma[4],
Email = delimitedByComma[5],
PhysicalDeliveryOfficeName = delimitedByComma[6]
}
}).ToList();;
I have the following columns in Entity Framework Code first approach:
public string LastName { get; set; }
public string FirstName { get; set; }
And I combine them into a full name:
public string FullName
{
get { return LastName + " " + FirstName; }
}
I don't even know if it's possible, but how I can generate a setter for this in order to send the values from the fullname to the other 2 columns when selecting it from e.g a dropdown list?
Say you would do a FullName.Split(' '); getting an array of names. It's all good when first and last names are single word. But how about John Billy Doe? Where does the LastName end and the FirstName begin?
Instead, you could use a different separator, like a comma: John, Billy Doe.
That way, doing a FullName.Split(','); would yield the correct Last Name and First Name.
public string FullName
{
get
{
return LastName + ", " + FirstName;
}
set
{
string[] names = value.Split(", ");
LastName = names[0];
FirstName = names[1];
}
}
EDIT: Of course, some validation is required for the value, but it's pretty hard to type code on the Android app (as I am doing). So, unless you need help with that, I leave it up to you.
The simpler approach would be to split on the first space you see, but it would break if anyone has a first or last name with a space in it. Broken first-names are rare, but last-names with spaces are common, e.g. "Jean-Claude Van Damme".
public String FullName {
set {
Int32 spaceIdx = value.IndexOf(" ");
if( spaceIdx == -1 ) {
this.FirstName = value;
this.LastName = "";
}
else
{
this.FirstName = value.Substring(0, spaceIdx);
this.LastName = value.Substring(spaceIdx + 1);
}
}
}
A better approach is to identify the names uniquely in your system and use that from your name-dropdown. Assuming this is ASP.NET MVC:
public class YourViewModel {
public IEnumerable<SelectListItem> Names { get; set; }
public Int32 SelectedNameByPersonId { get; set; }
}
In your controller:
public IActionResult YourAction() {
List<SelectListItem> names = db.People.Select( dbPerson => new SelectListItem() {
Text = dbPerson.FirstName + " " + dbPerson.LastName,
Value = dbPerson.Id.ToString()
} ).ToList(); // ToList so the DB is only queried once
return this.View( new YourViewModel() { Names = names } );
}
[HttpPost]
public IActionResult YourAction(YourViewModel model) {
DBPerson dbPerson = db.People.GetPerson( model.SelectedNameByPersonId );
// do stuff with person
}
In your view (aspx syntax):
<%= Html.DropDownFor( m => m.SelectNameByPersonId, this.Model.Names ) %>
I'm not exactly sure what you are asking, but I think this might help(plus input error handling).
public string LastName { get; set; }
public string FirstName { get; set; }
public string FullName
{
get
{
return LastName + " " FirstName;
}
series
{
var nameParts = value.Split(' ');
LastName = string.IsNullOrEmpty(nameParts[0]) ? string.Empty : nameParts[0];
FirstName = string.IsNullOrEmpty(nameParts[1]) ? string.Empty : nameParts[1];
}
}
I have tried for some workaround. Please try this and let me know of it works.
public string LastName { get; set; }
public string FirstName { get; set; }
[NotMapped] //This will make sure that entity framework will not map this to a new column
public string FullName
{
get { return LastName + " " + FirstName; }
// Here comes your desired setter method.
set
{
string[] str = value.Split(' ');
if (str.Length == 2)
{
FirstName = str[1];
LastName = str[0];
}
else if (str.Length >= 0 && value.Length > 0)
{
LastName = str[0];
}
else
throw new Exception("Invalid name");
}
}
I find it hard to clearly describe the case in a one-sentence title. Here is the example:
public class Person
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
public enum PersonProperties
{
FirstName = 1,
MiddleName = 2,
LastName = 3
}
I am hoping to do this:
foreach (var p in Persons) {
var nameCollection=new List<string>();
foreach (var s in (SectionsEnum[]) Enum.GetValues(typeof (SectionsEnum)))
{
nameCollection.Add(p.GetPropertyByName(s);
}
}
Now, how can we implement the GetPropertyByName() part?
You could do this directly using reflection:
public string GetPropertyByName(SectionsEnum s)
{
var property = typeof(Person).GetProperty(s.ToString());
return (string)property.GetValue(this);
}
Or maybe with a switch.
public string GetPropertyByName(SectionsEnum s)
{
switch (s)
{
case SectionsEnum.FirstName:
return this.FirstName;
case SectionsEnum.MiddleName:
return this.MiddleName;
case SectionsEnum.LastName:
return this.LastName;
default:
throw new Exception();
}
}
But I'd ask if you wouldn't be better served by a wholly different approach, e.g. a list:
public IList<string> NameProperties
{
get
{
return new[] { FirstName, MiddleName, LastName };
}
}
Or instead of having SectionsEnum, use Funcs:
//was
SectionsEnum s = SectionsEnum.FirstName;
//instead
Func<Person, string> nameFunc = p => p.FirstName;
string name = nameFunc(myPerson);
this should be a good starting point for you
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Person p = new Person() { FirstName ="a", MiddleName = "b", LastName = "c" };
List<string> result = new List<string>();
string[] enums = Enum.GetNames(typeof(PersonProperties));
foreach(string e in enums)
{
result.Add(p.GetType().GetProperty(e).GetValue(p, null).ToString());
}
int i = 0;
foreach (string e in enums)
{
Console.WriteLine(string.Format("{0} : {1}", e, result[i++]));
}
Console.ReadKey(false);
}
}
public class Person
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
public enum PersonProperties
{
FirstName = 1,
MiddleName = 2,
LastName = 3
}
}
I have the code below. I'd like to convert all items in this list to uppercase.
Is there a way to do this in Linq ?
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public class MyClass
{
List<Person> myList = new List<Person>{
new Person { FirstName = "Aaa", LastName = "BBB", Age = 2 },
new Person{ FirstName = "Deé", LastName = "ève", Age = 3 }
};
}
Update
I don't want to loop or go field by field. Is there a way by reflection to uppercase the value for each property?
Why would you like to use LINQ?
Use List<T>.ForEach:
myList.ForEach(z =>
{
z.FirstName = z.FirstName.ToUpper();
z.LastName = z.LastName.ToUpper();
});
EDIT: no idea why you want to do this by reflection (I wouldn't do this personally...), but here's some code that'll uppercase all properties that return a string. Do note that it's far from being perfect, but it's a base for you in case you really want to use reflection...:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public static class MyHelper
{
public static void UppercaseClassFields<T>(T theInstance)
{
if (theInstance == null)
{
throw new ArgumentNullException();
}
foreach (var property in theInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var theValue = property.GetValue(theInstance, null);
if (theValue is string)
{
property.SetValue(theInstance, ((string)theValue).ToUpper(), null);
}
}
}
public static void UppercaseClassFields<T>(IEnumerable<T> theInstance)
{
if (theInstance == null)
{
throw new ArgumentNullException();
}
foreach (var theItem in theInstance)
{
UppercaseClassFields(theItem);
}
}
}
public class Program
{
private static void Main(string[] args)
{
List<Person> myList = new List<Person>{
new Person { FirstName = "Aaa", LastName = "BBB", Age = 2 },
new Person{ FirstName = "Deé", LastName = "ève", Age = 3 }
};
MyHelper.UppercaseClassFields<Person>(myList);
Console.ReadLine();
}
}
LINQ does not provide any facilities to update underlying data. Using LINQ, you can create a new list from an existing one:
// I would say this is overkill since creates a new object instances and
// does ToList()
var updatedItems = myList.Select(p => new Person
{
FirstName = p.FirstName.ToUpper(),
LastName = p.LastName.ToUpper(),
Age = p.Age
})
.ToList();
If using LINQ is not principal, I would suggest using a foreach loop.
UPDATE:
Why you need such solution? Only one way of doing this in generic manner - reflection.
the Easiest approach will be to use ConvertAll:
myList = myList.ConvertAll(d => d.ToUpper());
Not too much different than ForEach loops the original list whereas ConvertAll creates a new one which you need to reassign.
var people = new List<Person> {
new Person { FirstName = "Aaa", LastName = "BBB", Age = 2 },
new Person{ FirstName = "Deé", LastName = "ève", Age = 3 }
};
people = people.ConvertAll(m => new Person
{
FirstName = m.FirstName?.ToUpper(),
LastName = m.LastName?.ToUpper(),
Age = m.Age
});
to answer your update
I don't want to loop or go field by field. Is there a way by
reflection to uppercase the value for each property?
if you don't want to loop or go field by field.
you could use property on the class to give you the Uppercase like so
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public string FirstNameUpperCase => FirstName.ToUpper();
public string LastNameUpperCase => LastName.ToUpper();
}
or you could use back field like so
public class Person
{
private string _firstName;
public string FirstName {
get => _firstName.ToUpper();
set => _firstName = value;
}
private string _lastName;
public string LastName {
get => _lastName.ToUpper();
set => _lastName = value;
}
public int Age { get; set; }
}
You can only really use linq to provide a list of new objects
var upperList = myList.Select(p=> new Person {
FirstName = (p.FirstName == null) ? null : p.FirstName.ToUpper(),
LastName = (p.LastName == null) ? null : p.LastName.ToUpper(),
Age = p.Age
}).ToList();
p.lastname.ToString().ToUpper().Contains(TextString)