I can't figure out how can I read items from the text file and put them into an int array. My objective is to count what is the average grade. To do so, I need to read the number which tells me how many grades does 1 student have, and then using that amount, read the grades themselves. For example, first column shows the amount of the grades, all remaining columns shows grades:
5;8;7;9;10;4
3;8;9;10
2;5;9
The code I wrote:
static void ReadData(out Student[] Student, out Faculty Faculty)
{
using (StreamReader read = new StreamReader(#"Data", Encoding.GetEncoding(1257)))
{
string line = null;
Student = new Student[Faculty.CMax];
Faculty = new Faculty();
while (null != (line = read.ReadLine()))
{
string[] values = line.Split(';');
string lastname = values[0];
string name = values[1];
string group = values[2];
int amount = int.Parse(values[3]);
int grades = int.Parse(values[4]);
Student studen = new Student(lastname, name, group, amount, grades);
Student.Take[Faculty.AmountOfStudents++] = studen;
}
}
}
I know that int[] grades = int.Parse(values[4]); is the problem. But I don't know how to fix it. Probably a newbie problem, thanks for the help.
After your clarification, it seems that you want to take:
Smith;John;XYZ;4;2;4;6;8
And retrieve the array of [2,4,6,8] so you can get the average from that.
If you can't do what I mention in my comment, then here's a workaround. Since the number of grades is irrelevant, just ignore it, and you'll recognize that you need an int array which contains 4 fewer items than the original. Then it's just a matter of copying them:
string[] fields = val.Split(';');
int[] grades = new int[fields.Length - 4];
for (int i = 4; i < fields.Length; ++i)
{
grades[i - 4] = int.Parse(fields[i]);
}
Or some other alternate versions if you're into LINQ:
string[] fields = val.Split(';');
int[] grades = Enumerable.Range(4, fields.Length - 4)
.Select(i => int.Parse(fields[i]))
.ToArray();
string[] fields = val.Split(';');
int[] grades = fields.Select((s, i) => new { s, i })
.Where(x => x.i >= 4)
.Select(x => int.Parse(x.s))
.ToArray();
Related
This question already has answers here:
The Most frequent Number in an array
(11 answers)
How do I find duplicates in an array and display how many times they occurred?
(14 answers)
Closed 1 year ago.
I'm trying to know the number that is most present in one array.
Example:
8 4 3 8 4 4 1 5
In this case, I want the program to tell me the number is 4.
This is what I've written so far, but the console.Writeline returns an error system.32.
Can you help ?
int[] moda = new int[21];
for (int j = 0; j < avaliacoes.Length; j++)
{
int avaliacao = avaliacoes[j];
moda[avaliacao] = moda[avaliacao] + 1;
}
Console.WriteLine("\nA moda é{0}: ", moda);
Grouping with some ordering on group size should get the job done.
To summarize what I am doing I am grouping the array by there values, I then Emit that group into an anonymous type that will hold the key as well as the group count. Third I order by descending so we order or enumerable from high value to low, which will allow me to say the first element in the enumeration must be the top value (if not equal to the top value).
class Program
{
static void Main(string[] args)
{
var a = new[] { 8, 4, 3, 8, 4, 4, 1, 5 };
var mostPresent = a
.GroupBy(e => e)
.Select(e => new { Key = e.Key, Count = e.Count() })
.OrderByDescending(e => e.Count)
.FirstOrDefault();
Console.WriteLine(mostPresent);
}
}
There are many methods for doing that, here is one:
static void Main(string[] args)
{
// Create array
const int arrLength = 10;
int[] mainArray = new int[arrLength];
// Fill array with random numbers
Random randNum = new Random();
for (int i = 0; i < mainArray.Length; i++)
{
mainArray[i] = randNum.Next(10);
}
// Create a dictionary for counting
Dictionary<int, int> countDic = new Dictionary<int, int>();
foreach (var currentNumber in mainArray)
{
// If the current number has appeared before increase the count for that number
if (countDic.TryGetValue(currentNumber, out int _))
{
countDic[currentNumber]++;
}
// If it's first time current number has appeared set its count as one
else
{
countDic.Add(currentNumber, 1);
}
}
// Print frequency of numbers
foreach (var num in countDic)
{
Console.WriteLine($"{num.Key} appears {num.Value} times in the array!");
}
// Print the number which appears the most in the array
int maxNum = countDic.Aggregate((x, y) => x.Value > y.Value ? x : y).Key;
Console.WriteLine(maxNum);
Console.Read();
}
Ask me if there is anything that you can not understand in the solution
You can do that easily with LINQ. I'll explain what happens below:
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
List<int> ints = new List<int> { 8, 4, 3, 8, 4, 4, 1, 5 };
var query = from i1 in ints
select new
{
number = i1,
count = ints.Where(i2 => i2 == i1).Count()
};
var most = query.OrderByDescending(x => x.count).First().number;
Console.WriteLine($"Number: {most}");
Console.ReadKey();
}
}
}
In the first query I iterate over all ints in the list and create an anonymous object with 2 properties 'number' and 'count'. The count contains the amount of ints in the list with the number of the first iteration.
In the second line the 'most'is selected by ordering the anonymous types in descending order on 'count' and taking the First item of that result. If you have more numbers in your array with the same number of entries you will get only the first one. So if '4' and 5' both are present 4 times it is not guaranteed which result you will get. It could be '4' but just as well '5'.
I have a class that has a bunch of different variables and a couple lists 1 in particular holds ints(positionInts)
I also have a list(teamsList) for holding objects I have created from that class
now I would like to sort the team's list by positions values
Hopefully, I'm not being too vague as the project I'm working on is full of not well-written code so it can be hard to explain.
This function orders the list according to your precondition.
private List<String> OrderList(List<String> teams, int[] positions)
{
List<String> orderedTeams;
Dictionary<int, string> teamsToOrder = new Dictionary<int, string>();
int position = 0;
foreach (string team in teams)
{
teamsToOrder.Add(positions[position], teams[position]);
position = position + 1;
}
orderedTeams = teamsToOrder.OrderByDescending(team => team.Key).Select(team => team.Value).ToList();
return orderedTeams;
}
If I understand your question correctly, then you have list of arbitrary type, for example list of strings:
var teamsList = new List<String> { "team1", "team2", "team3", "team4" };
Next up, you have enumeration of integers:
var positionInts = new[] { 2, 3, 1, 0 };
And your goal is to order teamsList based on sequence numbers of the positionInts. In that case you can use following method:
static IEnumerable<T> OrderBySequence<T>(IEnumerable<T> source, IEnumerable<Int32> sequence)
{
for (var i = 0; i < Math.Min(source.Count(), sequence.Count()); i++)
{
var s = sequence.ElementAt(i);
if (s > -1 && s < source.Count())
{
yield return source.ElementAt(s);
}
}
}
Which will produce:
team3
team4
team2
team1
We Have 2 dimensional string array like
"0" => {"John","23"},
"1" => {"Doe","12"},
"2" => {"Maria","41"},
.......
We want to sort this array like
"0" => {"Maria","41"},
"1" => {"John","23"},
"2" => {"Doe","12"},
.......
Our Array Code String[,] kelimedeger = new String[20, 2];
We want order by kelimedeger[i,1]
Regarding Sorting
One of the problems I see here is that your second "string" is actually not a string, but rather a number. As such, you actually have a person with a name and an age.
Why does this matter?
Sorting depends on the types of data. Strings are sorted alphabetically, while numbers are sorted numerically.
Consider the following list:
1, 2, 17, 11, 100, 20, 34
This can be sorted in multiple ways
Numerical Alphabetical
--------- ------------
1 1
2 100
11 11
17 17
20 2
34 20
100 34
Given that you will most likely want to sort numerically, you need to store your data as int, not as string.
How to store the data?
This depends on your use-case. If names are guaranteed to be unique, then you could use a Dictionary<string,int>. Otherwise, I advise you to create a class Person and use a ICollection<Person> to store them.
As Dictionary<string, int>
This approach is useful if names are guaranteed to be unique in your domain. Further, it only uses built-in types.
namespace DictionaryTest
{
public class Program
{
public static void Main(string[] args)
{
//Create a dictionary to store people
Dictionary<string, int> people = new Dictionary<string, int>();
//Add some people. Note that this is type-safe
people.Add("John", 23);
people.Add("Doe", 12);
people.Add("Maria", 41);
//people.Add("John", 55); // <-- This will fail because there is already a John
//Create queries to ensure correct sorting
var peopleByName = from p in people
orderby p.Key //Our name is the key, the age is the value
select new {Name = p.Key, Age = p.Value};
var peopleByAge = from p in people
orderby p.Value
select new {Name = p.Key, Age = p.Value};
var peopleByAgeDescending = from p in people
orderby p.Value descending
select new {Name = p.Key, Age = p.Value};
//Execute the query and print results
foreach(var person in peopleByAge)
{
Console.WriteLine("Hello, my name is {0} and I am {1} years old", person.Name, person.Age);
}
}
}
}
Try it online!
As ICollection<Person>
This approach defines a class Person, which only holds a Name and an Age property, but can be extended to contain much more information, methods, etc.
namespace ClassTest
{
public class Program
{
public static void Main(string[] args)
{
//Create a list to store people
ICollection<Person> people = new List<Person>();
//Add some people. Note that this is type-safe
people.Add(new Person(){ Name = "John", Age = 23, FavouriteColour = "Blue" });
people.Add(new Person(){ Name = "Doe", Age = 12});
people.Add(new Person(){ Name = "Maria", Age = 41, FavouriteColour = "Purple" });
people.Add(new Person(){ Name = "John", Age = 55, FavouriteColour = "Gray" }); //<-- You can indeed have two people with the same name
//Create queries to ensure correct sorting
var peopleByName = from p in people
orderby p.Name
select p;
var peopleByAge = from p in people
orderby p.Age
select p;
var peopleByAgeDescending = from p in people
orderby p.Age descending
select p;
//Execute the query and print results
foreach(var person in peopleByAge)
{
Console.WriteLine("Hello, my name is {0} and I am {1} years old.", person.Name, person.Age);
if(person.FavouriteColour != null)
{
Console.WriteLine("My favourite colour is {0}.", person.FavouriteColour);
}
else
{
Console.WriteLine("I have no favourite colour.");
}
Console.WriteLine(); //Add a new line for better readability
}
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string FavouriteColour { get; set; }
}
}
Try it online!
I personally like the second approach better, as it is more extendable and does not have a requirement for uniqueness of the name. It allows you to extend the Person class as much as you like, and gives you many more options for sorting.
To sort a two-dimensional array you need to convert each row to a one-dimensional array and save it in a List or something similar. Then you can sort the list by the column. After sorting you need to convert the list back to a two-dimensional array.
Here is a method you could use for sorting:
public static T[,] Sort2DArray<T>(T[,] array, int column, bool ascending = true)
{
int i = 0;
List<T[]> items = new List<T[]>();
int columns = array.GetLength(1);
int rows = array.GetLength(0);
T[] obj = new T[columns];
foreach (var item in array)
{
obj[i % columns] = item;
if ((i + 1) % 2 == 0)
{
items.Add(obj);
obj = new T[columns];
}
i++;
}
var ordered = ascending ? items.OrderBy(a => a[column]) : items.OrderByDescending(a => a[column]);
T[,] result = new T[rows, columns];
for (int r = 0; r < rows; r++)
{
var row = ordered.ElementAt(r);
for (int c = 0; c < columns; c++)
{
result[r, c] = row[c];
}
}
return result;
}
Your code would look like this:
string[,] array =
{
{"John", "23" },
{"Doe", "12" },
{"Maria", "41" },
};
string[,] ordered = Sort2DArray(array, 1);//Sort by column 1 / Age
Converting a two-dimensional array to one- dimensional array and back is not the best routine to sort your values. The best way is to create a class to store your data, just as David Stockinger and Tim Schmelter said.
I m in a situation where i need to find record from a generic list using its position, means need to find 1st 5th and 9th record , then 2nd 6th and 10th record and so on...
Situation is
A list of projects assigned to a List of Team,
So if we have 20 projects and 4 teams
then 1st project go to 1st team, 2nd go to 2nd team , 3rd go to 3rd team, 4th go to 4th team
then again 5th project go to 1st team
so its like
Projects Team
1 1
2 2
3 3
4 4
5 1
6 2
7 3
8 4
9 1
.
.
so now i want to run a Query on Generic List to get record for each team, so for first team record 1,5 and 9.... need to fetch.
Some thing like
List<Project> lst = list (from Database)
//For 1stTeam
lst = lst.Index(1,5,9...);
//For 2nsTeam
lst = lst.Index(2,6,10...);
Hope i clear my point.
You could do something like this with LINQ Select and GroupBy:
List<int> list = new List<int>{1,2,3,4,5,6,7,8,9,10};
int numberOfTeams = 4;
var projectsByTeam = list
.Select((number, index) => new {Value = number, Index = index})
.GroupBy(item => item.Index % numberOfTeams)
.Select(item => new {TeamNumber = item.Key+1, ProjectIDs = item.Select(x => x.Value).ToList()})
.ToList();
Splits the original list into
{
{TeamNumber = 1, ProjectIDs = {1,5,9}},
{TeamNumber = 2, ProjectIDs = {2,6,10}},
{TeamNumber = 3, ProjectIDs = {3,7}},
{TeamNumber = 4, ProjectIDs = {4,8}},
}
First, this is not specific to generic lists.
You have to create a new list, and then, one by one, add the items from the original list that you want in the new list. You can access single items at a given position via the indexer (square brackets).
List<Project> lst = // list (from Database)
List<Project> firstTeam = new List<Project>();
firstTeam.Add(lst[1]);
firstTeam.Add(lst[5]);
firstTeam.Add(lst[9]);
List<Project> secondTeam = new List<Project>();
secondTeam.Add(lst[2]);
secondTeam.Add(lst[6]);
secondTeam.Add(lst[10]);
Of course, if the items are distributed that regularly throughout the original lst, you can automatically determine the items:
List<Project> firstTeam = new List<Project>();
for (int i = 1; i < lst.Count; i += 4) {
firstTeam.Add(lst[i]);
}
i.e. you loop over the original list, taking every 4th item.
If the items to add to one of the teams are not distributed regularly throughout lst, you will have to add them one by one, but you might be able to make use of the shorter list initializer syntax:
List<Project> firstTeam = new List<Project>() { lst[1], lst[5], lst[9] };
Lastly, note that List<T> starts counting indices at zero, so the very first item is lst[0], not lst[1].
You are looking for the params keyword. It will allow you to pass in to Index an array of arguments, which are the indexes in your case.
In your case an extension method can do the trick:
public static List<Project> Index(this List<Project> list, params int[] indexes)
{
var newList = new List<Project>();
foreach(var index in indexes)
{
newList.Add(list[index]);
}
return newList;
}
// Define other methods and classes here
static IEnumerable<IEnumerable<T>> CustomSplit<T>(this IEnumerable<T> source, int max)
{
var results = new List<List<T>>();
for (int i = 0; i < max; i++)
{
results.Add(new List<T>());
}
int index = 0;
using (var enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
int circularIndex = index % max;
results[circularIndex].Add(enumerator.Current);
index++;
}
}
return results;
}
And here is how to use it:
void Main()
{
var elements = Enumerable.Range(0, 100).CustomSplit(4);
}
You can use:
List<Project> projects; // = something from db
var neededIndexes = new[] { 0, 4, 8 };
var result = projects.Where((project, index) => neededIndexes.Contains(index)).ToList();
Or if the indexes are evenly distributed:
List<Project> projects; // = something from db
var result = projects.Where((project, index) => index % 4 == 0).ToList();
This solve your problem:
List for each team:
List<List<Project>> projectsPerTeam = new List<List<Project>> ();
for(int i=0;i<teamsList.Count();i++)
{
projectsPerTeam.Add(new List<Project> ());
}
Now your issue (add project for correct team):
for(int i=0;i<projectsList.Count();i++)
{
projectsPerTeam[i%teamList.Count()].Add(projectsList[i]);
}
First of all sorry for my mistakes in English its not my primary language
i have a problem , i have a array like following
string[] arr1 = new string[] {
"Pakistan:4,India:3,USA:2,Iran:1,UK:0",
"Pakistan:4,India:3,USA:2,Iran:1,UK:0",
"India:4,USA:3,Iran:2,UK:1,Pakistan:0"
};
now i just want to know that how many times Pakistan comes with 1 ,
how many times with 2 , 3 , 4
and i need to know this about all India , USA , Iran , UK
Thanks in advance , you guys are my last hope .
This linq will convert the array into a Dictionary>, where the outer dictionary contains the countries names, and inner dictionaries will contain the ocurrence number (the number after ':') and the count for each ocurrence.
string[] arr1 = new string[]
{
"Pakistan:4,India:3,USA:2,Iran:1,UK:0",
"Pakistan:4,India:3,USA:2,Iran:1,UK:0",
"India:4,USA:3,Iran:2,UK:1,Pakistan:0"
};
var count = arr1
.SelectMany(s => s.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
.GroupBy(s => s.Split(':')[0], s => s.Split(':')[1])
.ToDictionary(g => g.Key,
g =>
{
var items = g.Distinct();
var result = new Dictionary<String, int>();
foreach (var item in items)
result[item] = g.Count(gitem => gitem == item);
return result;
});
// print the result
foreach(var country in count.Keys)
{
foreach(var ocurrence in count[country].Keys)
{
Console.WriteLine("{0} : {1} = {2}", country, ocurrence, count[country][ocurrence]);
}
}
I would use the String.Split(char[]) method and the String.SubString(int, int) method to inspect every 'country' inside your array and to get the number postfix of each country.
Try the following:
(The following code is now compiled and tested.)
Use a simple data structure to facilitate the task of holding the result of your operation.
public struct Result {
string Country { get; set; }
int Number { get; set; }
int Occurrences { get; set; }
}
// define what countries you are dealing with
string[] countries = new string[] { "Pakistan", "India", "USA", "Iran", "UK", }
Method to provide the overall result:
public static Result[] IterateOverAllCountries () {
// range of numbers forming the postfix of your country strings
int numbersToLookFor = 4;
// provide an array that stores all the local results
// numbersToLookFor + 1 to respect that numbers are starting with 0
Result[] result = new Result[countries.Length * (numbersToLookFor + 1)];
string currentCountry;
int c = 0;
// iterate over all countries
for (int i = 0; i < countries.Length; i++) {
currentCountry = countries[i];
int j = 0;
// do that for every number beginning with 0
// (according to your question)
int localResult;
while (j <= numbersToLookFor) {
localResult = FindCountryPosition(currentCountry, j);
// add another result to the array of all results
result[c] = new Result() { Country = currentCountry, Number = j, Occurrences = localResult };
j++;
c++;
}
}
return result;
}
Method to provide a local result:
// iterate over the whole array and search the
// occurrences of one particular country with one postfix number
public static int FindCountryPosition (string country, int number) {
int result = 0;
string[] subArray;
for (int i = 0; i < arr1.Length; i++) {
subArray = arr1[i].Split(',');
string current;
for (int j = 0; j < subArray.Length; j++) {
current = subArray[j];
if (
current.Equals(country + ":" + number) &&
current.Substring(current.Length - 1, 1).Equals(number + "")
)
result++;
}
}
return result;
}
The following should enable you to run the algorithm
// define what countries you are dealing with
static string[] countries = new string[] { "Pakistan", "India", "USA", "Iran", "UK", };
static string[] arr1 = new string[] {
"Pakistan:4,India:3,USA:2,Iran:1,UK:0",
"Pakistan:4,India:3,USA:2,Iran:1,UK:0",
"India:4,USA:3,Iran:2,UK:1,Pakistan:0"
};
static void Main (string[] args) {
Result[] r = IterateOverAllCountries();
}
The data structure you are using is not rich enough to provide you with that information. Hence you need to parse your string and create a new data structure to be able to provide (sring[][]):
string[] arr1 = new string[] {
"Pakistan,India,USA,Iran,UK",
"Pakistan,India,USA,Iran,UK",
"India,USA,Iran,UK,Pakistan"
};
string[][] richerArray = arr1.Select(x=> x.Split('\'')).ToArray();
var countPakistanIsFirst = richerArray.Select(x=>x[0] == "Pakistan").Count();
UPDATE
You seem to have changed your question. The answer applies to the original question.