Let's Assume I have Multi dimensional Object array that represents employee information for example
String[,] Employee= new object[,] {
{"john","MBA#MBA#BE#MBA#BE"},
{"jan","MS#MSC#MBA"},
};
Visualize
john MBA#MBA#BE#MBA#BE
jan MS#MSC#MBA
I want remove the duplicated data ( where data is divided by #)
john MBA#BE
jan MS#MSC#MBA
For this scenario it's better to use a dictionary:
Dictionary<string, string> employee = new Dictionary<string, string>()
{
{"john", "MBA#MBA#BE#MBA#BE"},
{"jan", "MS#MSC#MBA"}
}
Dictionary<string, string> result = new Dictionary<string, string>();
foreach (var kvp in employee)
{
result[kvp.Key] = string.Join("#", kvp.Value.Split('#').Distinct());
}
The result dictionary will contain the result:
// Prints "MS#MSC#MBA"
Console.WriteLine(result["jan"]);
// Prints "MBA#BE"
Console.WriteLine(result["john"]);
Personally I'd create a class to hold that information
public class Employee
{
public Employee(string name)
{
Name = name;
Degress = new HashSet<string>();
}
public string Name { get; private set; }
public HashSet<string> Degrees { get; private set; }
}
Then you can populate a list of them like this
string[,] employeeArray = { { "john", "MBA#MBA#BE#MBA#BE" }, { "jan", "MS#MSC#MBA" } };
List<Employee> employees = new List<Employee>();
for (int i = 0; i < employeeArray.GetLength(0); i++)
{
Employee employee = new Employee(employeeArray[i,0]);
foreach (var degree in employeeArray[i, 1].Split('#'))
{
employee.Degrees.Add(degree);
}
employees.Add(employee);
}
foreach (var e in employees)
{
Console.WriteLine(e.Name + " " + string.Join(" ", e.Degress));
}
Which prints
john MBA BE
jan MS MSC MBA
Because Degrees is a HashSet it will not allow duplicates, and when you attempt to pass a duplicate to Add it will just return false.
Related
public void CalcolaTurni()
{
Dictionary<string, int> dict = new Dictionary<string, int>();
dict.Add("1", DestrezzaGiocatore1);
dict.Add("2", DestrezzaGiocatore2);
foreach (var item in dict.OrderByDescending(r => r.Value))
{
Console.WriteLine("Key: {0}, Value: {1}", item.Key, item.Value);
array.Add(item.value)
}
}
This is what I have done so far. I'm using a dictionary to store the name of the player and its dexterity and an array to store each dexterity value to sort it.
Okay let's say I have three players and their respective speed. I'd like to store each name as a key and each value as their speed (int) in a dictionary. Then I'd like to somehow find which one of them has the highest speed value and return its name. For example: Carl:10 Mark:12 John:11 -> Mark
Encapsulate the player and their properties together in a class rather than keeping them together with a dictionary, it'll make it easier to work with.
For example, create a class to model player stats:
public class PlayerStats
{
public string PlayerId { get; set; }
public int Dexterity { get; set; }
}
Then you can use it like this:
public static void Main()
{
var DestrezzaGiocatore1 = 5;
var DestrezzaGiocatore2 = 1;
var DestrezzaGiocatore3 = 6;
List<PlayerStats> playerStats = new List<PlayerStats>()
{
new PlayerStats() { PlayerId = "1", Dexterity = DestrezzaGiocatore1 },
new PlayerStats() { PlayerId = "2", Dexterity = DestrezzaGiocatore2 },
new PlayerStats() { PlayerId = "3", Dexterity = DestrezzaGiocatore3 }
};
var statsSorted = playerStats.OrderByDescending(a => a.Dexterity);
Console.WriteLine($"Player {statsSorted.First()} has the highest dexterity: {statsSorted.First().Dexterity}");
foreach (var playerStat in statsSorted)
{
Console.WriteLine($"Player {playerStat.PlayerId}: {playerStat.Dexterity}");
}
Console.ReadKey();
}
I have a class and an array of property names defined as follows:
public class Dog {
public string Name { get; set; }
public string Breed { get; set; }
public int Age { get; set; }
}
var desiredProperties = new [] {"Name", "Breed"};
I also have a method that returns a list of dog objects:
List<Dog> dogs = GetAllDogs();
Is there an way I can return a subset of dogs that only contain the properties defined within the desiredProperties array? Eventually, this resulting list will be serialized to JSON.
I have been struggling with this problem for some time now, considering that the user will be allowed to specify any combination of properties (assuming they are all valid) as the output within the array. Some more examples:
var desiredProperties = new [] {"Name", "Age"};
// Sample output, when serialized to JSON:
// [
// { Name: "Max", Age: 5 },
// { Name: "Spot", Age: 2 }
// ]
var desiredProperties = new [] {"Breed", "Age"};
// [
// { Breed: "Scottish Terrier", Age: 5 },
// { Breed: "Cairn Terrier", Age: 2 }
// ]
you can write a function to do that. Use the extension method below.
public static class Extensions
{
public static object GetPropertyValue(this object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName).GetValue(obj);
}
public static List<Dictionary<string, object>> FilterProperties<T>(this IEnumerable<T> input, IEnumerable<string> properties)
{
return input.Select(x =>
{
var d = new Dictionary<string, object>();
foreach (var p in properties)
{
d[p] = x.GetPropertyValue(p);
}
return d;
}).ToList();
}
}
Test it like
var dogs = GetAllDogs();
var f1 = dogs.FilterProperties(new[]
{
"Name", "Age"
});
var f2 = dogs.FilterProperties(new[]
{
"Breed", "Age"
});
Console.WriteLine(JsonConvert.SerializeObject(f1));
Console.WriteLine(JsonConvert.SerializeObject(f2));
and result is
[{"Name":"Spot","Age":2},{"Name":"Max","Age":5}]
[{"Breed":"Cairn Terrier","Age":2},{"Breed":"Scottish Terrier","Age":5}]
I don't have a clue if this is the most efficient way to do it, but it's a way of doing it:
var list = new List<Dog>();
list.Add(new Dog {Name = "Max", Breed = "Bull Terrier", Age = 5});
list.Add(new Dog {Name = "Woofie", Breed = "Collie", Age = 3});
var desiredProperties = new[] {"Name", "Breed"};
var exportDogs = new List<Dictionary<string, object>>();
foreach(var dog in list)
{
var exportDog = new Dictionary<string, object>();
foreach(var property in desiredProperties)
{
exportDog[property] = dog.GetType().GetProperty(property).GetValue(dog, null);
}
exportDogs.Add(exportDog);
}
var output = JsonConvert.SerializeObject(exportDogs);
The output will look like this:
[{"Name":"Max","Breed":"Bull Terrier"},{"Name":"Woofie","Breed":"Collie"}]
If, however, you don't need to dynamically access properties, it's a lot better to do something like this:
var output = list.Select(dog => new {dog.Name, dog.Breed});
Then just serialize the output.
something like this...not tested...
var desiredProperties = new [] {"Name", "Breed"};
var lst = (from asm in AppDomain.CurrentDomain.GetAssemblies()
from asmTyp in asm.GetTypes()
where typeof(dog).IsAssignableFrom(asmTyp) && desiredProperties.All(p=> PropertyExists(asmTyp, p))
select asmTyp).ToArray();
private bool PropertyExists(Type dogType, string name)
{
bool ret=true;
try{ dogType.GetProperty(name);}
catch{ret=false};
return ret;
}
I'm working on a homework problem for my computer science class. A cities census data is on a text file holding records for its citizens. Each line will have four fields(age, gender, marital status, and district) of different data types separated by a comma. For example, 22, F, M, 1.
How should I approach this? My thoughts are that I should use two 1D arrays, one for age and one for district. I need to be able to later count how many people are in each district, and how many people are in different age groups for the whole city.
How do I read each line and get the info I want into each array?
edit**
This is what I've managed to do so far. I'm trying to separate my data from fields into four different arrays. This is where I'm stuck.
FileStream fStream = new FileStream("test.txt", FileMode.Open, FileAccess.Read);
StreamReader inFile = new StreamReader(fStream);
string inputRecord = "";
string[] fields;
int[] ageData = new int[1000];
string[] genderData = new string[1000];
string[] maritalData = new string[1000];
int[] districtData = new int[1000];
inputRecord = inFile.ReadLine();
while (inputRecord != null)
{
fields = inputRecord.Split(',');
int i = 0;
ageData[i] = int.Parse(fields[0]);
genderData[i] = fields[1];
maritalData[i] = fields[2];
districtData[i] = int.Parse(fields[3]);
i++;
inputRecord = inFile.ReadLine();
}
edit 2**
First question, I've decided to use the below code to find out how many citizens are in each district of the census data.
for (int x = 1; x <= 22; x++)
for (int y = 0; y < districtData.Length; y++)
if (districtData[y] == x)
countDist[x]++;
for (int x = 1; x <= 22; x++)
Console.WriteLine("District " + x + " has " + countDist[x] + " citizens");
In my .Writeline when x reaches two digits it throws off my columns. How could I line up my columns better?
Second question, I am not quite sure how to go about separating the values I have in ageData into age groups using an if statement.
It sounds like each of the four fields have something in common... they represent a person surveyed by the census. That's a good time to use a class along the lines of
public class Person
{
public int Age { get; set; }
public string Gender { get; set; }
public string MaritalStatus { get; set; }
public int District { get; set; }
}
Then, just read in all of the lines from the text file (if it's small, it's fine to use File.ReadAllLines()), and then create an instance of Person for each line in the file.
You can create a
List<Person> people;
to hold the Person instances that you parse from the text file.
Since the lines appear to be separated by commas, have a look at String.Split().
UPDATE
The attempt in your edit is pretty close. You keep creating a new i and initializing it to 0. Instead, initialize it outside your loop:
int i = 0;
while (inputRecord != null)
{
fields = inputRecord.Split(',');
Also you may want to trim excess spaces of of your input. If the fields are separated with ", " rather than just "," you will have excess spaces in your fields.
genderData[i] = fields[1].Trim();
maritalData[i] = fields[2].Trim();
How about this?
List<string[]> o = File.ReadAllLines(#"C:\TestCases\test.txt").Select(x => x.Split(',')).OrderBy(y => y[0]).ToList();
Each person is a string array in the list.
Each property is a index in the array eg: age is first.
The above code reads all lines comma delimits them orders them by age and adds them to the list.
public static class PersonsManager
{
public static PersonStatistics LoadFromFile(string filePath)
{
var statistics = new PersonStatistics();
using (var reader = new StreamReader(filePath))
{
var separators = new[] { ',' };
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if (string.IsNullOrWhiteSpace(line))
continue; //--malformed line
var lParts = line.Split(separators, StringSplitOptions.RemoveEmptyEntries);
if (lParts.Length != 4)
continue; //--malformed line
var person = new Person
{
Age = int.Parse(lParts[0].Trim()),
Gender = lParts[1].Trim(),
MaritalStatus = lParts[2].Trim(),
District = int.Parse(lParts[3].Trim())
};
statistics.Persons.Add(person);
}
}
return statistics;
}
}
public class PersonStatistics
{
public List<Person> Persons { get; private set; }
public PersonStatistics()
{
Persons = new List<Person>();
}
public IEnumerable<Person> GetAllByGender(string gender)
{
return GetByPredicate(p => string.Equals(p.Gender, gender, StringComparison.InvariantCultureIgnoreCase));
}
//--NOTE: add defined queries as many as you need
public IEnumerable<Person> GetByPredicate(Predicate<Person> predicate)
{
return Persons.Where(p => predicate(p)).ToArray();
}
}
public class Person
{
public int Age { get; set; }
public string Gender { get; set; }
public string MaritalStatus { get; set; }
public int District { get; set; }
}
Usage:
var statistics = PersonsManager.LoadFromFile(#"d:\persons.txt");
var females = statistics.GetAllByGender("F");
foreach (var p in females)
{
Console.WriteLine("{0} {1} {2} {3}", p.Age, p.Gender, p.MaritalStatus, p.District);
}
I hope it helps.
Requirement:I have two string array. Array of empDetails contain four field assume field one is ID and other fields are details. Array of empToRemove contain IDs of employee to remove. Create string of array which will not contain IDs which are present in empToRomove array. Please note I have to use this code which contain more than 100000 data in empDetails and more then 20000 data in empToRemove.
Any suggestion much appropriated.
string[] empDetails = { "1,abc,2,11k", "2,de,3,11k", "3,abc,2,18k", "4,abdc,2,12k" };
string[] empToRemove = { "1","3" };
My Solution
class Program
{
static void Main(string[] args)
{
string[] empDetails = { "1,abc,2,11k", "2,de,3,11k", "3,abc,2,18k", "4,abdc,2,12k" };
string[] empToRemove = { "1","3" };
//Add emp details in list of employee
List<emp> e = new List<emp>();
foreach (var item in empDetails)
{
Dictionary<int, string> tempEmployee = new Dictionary<int, string>();
int i = 1;
foreach (string details in item.Split(','))
{
tempEmployee.Add(i, details);
i++;
}
e.Add(new emp { ID = int.Parse(tempEmployee[1]), Details1 = tempEmployee[2], Details2 = tempEmployee[3], Details3 = tempEmployee[4] });
}
foreach (string item in empToRemove)
{
emp employeeToRemove = e.Where(x => x.ID == int.Parse(item)).Single();
e.Remove(employeeToRemove);
}
foreach (var item in e)
{
Console.WriteLine(item.ID + item.Details1 + item.Details2 + item.Details3);
}
Console.ReadLine();
}
}
class emp
{
public int ID { get; set; }
public string Details1 { get; set; }
public string Details2 { get; set; }
public string Details3 { get; set; }
}
Thanks
If I correctly understood your requirement and the only thing you need - is to print (or manipulate somehow else) elements of empDetails which ID's not in empToRemove - than your code is totally overkill.
Following will be pretty sufficient:
string[] empDetails = { "1,abc,2,11k", "2,de,3,11k", "3,abc,2,18k", "4,abdc,2,12k" };
string[] empToRemove = { "1", "3" };
var remove = new HashSet<string>(empToRemove);
foreach (var item in empDetails)
{
string id = item.Substring(0, item.IndexOf(','));
if (!remove.Contains(id))
Console.WriteLine(item); // or your custom action with this item
}
string[] empDetails = { "1,abc,2,11k", "2,de,3,11k", "3,abc,2,18k", "4,abdc,2,12k" };
string[] empToRemove = { "1","3" };
foreach (string item in empToRemove)
empDetails = empDetails.Where(val => val.Substring(0, val.IndexOf(',')) != item).ToArray();
Is one way. Cant get more effeciant than that?
based on research from:
How to delete an element from an array in C#
I'm trying to figure out how to build a multi-dimensional "array" that is:
flexible size
use 2 keys
1st key is int (flexible)
2nd key is string (kind of limited)
The use will be like:
console.writelen(array[0]["firstname"]);
console.writelen(array[0]["lastname"]);
console.writelen(array[0]["phone"]);
console.writelen(array[1]["firstname"]);
console.writelen(array[1]["lastname"]);
console.writelen(array[1]["phone"]);
.....
.....
console.writelen(array[x]["firstname"]);
console.writelen(array[x]["lastname"]);
console.writelen(array[x]["phone"]);
Are you sure it wouldn't be more appropriate to create a class/struct to contain the data? For example:
class Person
{
public string FirstName
{
get;
set;
}
public string LastName
{
get;
set;
}
public string Phone
{
get;
set;
}
}
Then you'd just create an array of Person:
var array = new Person[1];
array[0] = new Person() { FirstName = "Joe", LastName = "Smith", Phone = "foo" };
Or, since you say "flexible size", maybe you'd want a list instead:
var list = new List<Person>();
list.Add(new Person());
Update: The syntax used to set array[0] in the first example is an object initializer; the following two snippets are roughly equivalent:
var foo = new Person();
foo.FirstName = "John";
var bar = new Person() { FirstName = "John" };
So yes, you could just call list.Add(new Person() { ... }) if you wanted to. You could also make use of collection initializers in this case:
var john = new Person() { FirstName = "John" };
var joe = new Person() { FirstName = "Joe" };
var list = new List<Person>() { john, joe };
You can simply use this:
Dictionary<int, Dictionary<string, string>>
Use it like this:
var dd = new Dictionary<int, Dictionary<string, string>>();
dd[5] = new Dictionary<string, string>();
dd[5]["a"] = "foo";
You can also create a new class to simplify the creation of the inner dictionary:
class DDict { // optional: generic
private readonly Dictionary<int, Dictionary<string, string>> _Inner = new ...;
public Dictionary<string, string> this (int index) {
Dictionary<string, string> d;
if (!_Inner.TryGetValue(index, out d)) {
d = new Dictionary<string, string>();
_Inner.Add(index, d);
}
return d;
}
}
var dd = new DDict();
dd[5]["a"] = "hi";
If the first index is sequential, you can of course also just use an array of dictionaries:
var dd = new Dictionary<string, string>[128];
Also, if the inner members are always the same, I suggest to create a new class and access it in an array:
class Dat {
string name;
string phone;
}
var list = new Dat[128]
// access:
list[5].name = "matt";
Instead of an array, you could also use a List or a Dictionary<int, Dat> in that case.
I don't believe you can do this with an Array unless you have a single Array of KeyValuePair<int,string>, but I think you really want a Dictionary<int,string>.
var dic = new Dictionary<int,string>();
dic[0] = "zero";
dic[1] = "one";
dic[2] = "two";
foreach(KeyValuePair<int,string> kvp in dic)
{
Console.WriteLine(String.Format("Key: {0}, Value: {1}",kvp.Key,kvp.Value);
}
Actually i just see two dimensions. The first one is a row index, the second is a column index. And this sounds like a DataTable to me.