C# Replace String.Split [closed] - c#

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I have a string with this format "10,2/20,5/50,3"
Those are wins of every player.
"roomPrize,wins/nextRoomPrize,wins" etc
I figured out how to read it but I want to change the amount of wins for some roomPrize. I've come this far.
winsRawData = getStatW.text; //That is the wins string formated as explained above
string[] winSplits = winsRawData.Split('/');
for(int i = 0; i < winSplits.Length; i++)
{
if(winSplits[i].Split(',')[0] == room.ToString()) //room is the roomPrize that i want to affect
{
//newWins is the new win count that I want to update with
//winSplits[i].Split(',')[1] == newWins; <-- I just need to do that
}
}
Thanks

If I understood your question well, you would like to do the following:
winSplits[i].Split(',')[1] = newWins;
In order to achieve this, you would need to split the value, then re-create it (e.g. Join) and put it back in the original array.
The following should do the trick:
winsRawData = getStatW.text; //That is the wins string formated as explained above
string[] winSplits = winsRawData.Split('/');
for (int i = 0; i < winSplits.Length; i++)
{
var dataArray = winSplits[i].Split(',');
if (dataArray[0] == room.ToString()) //room is the roomPrize that i want to affect
{
// sets the new value.
dataArray[0] = newWins;
}
// finalize by recreating the string and push it back to the original array
winSplits[i] = String.Join(",", dataArray);
}
Edit Using the following values:
var winsRawData = "10,2/20,5/50,3";
int room = 10;
int newWins = 100;
And by adding the var output = String.Join("/", winSplits); at the end of the above code, you will get a string output:
"100,2/20,5/50,3"
See the code below for a complete example:
string[] winSplits = winsRawData.Split('/');
for (int i = 0; i < winSplits.Length; i++)
{
var dataArray = winSplits[i].Split(',');
if (dataArray[0] == room.ToString()) //room is the roomPrize that i want to affect
{
// sets the new value.
dataArray[0] = newWins.ToString();
}
// finalize by recreating the string and push it back to the original array
winSplits[i] = String.Join(",", dataArray);
}
var output = String.Join("/", winSplits); // = "100,2/20,5/50,3"

you should first refactor to deserialize the data into some Player objects, change it's wins count and then serialize it back:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
// Raw data
string rawData = "10,2/20,5/50,3";
// First split
string[] playersRaw = rawData.Split('/');
// Initialize a collection for the player objects
var players = new List<Player>();
// Iterates over the splitted players data
foreach (var playerRaw in playersRaw)
{
// Deserialize each player
var playerDeserialized = Player.Deserialize(playerRaw);
// Store the player data into the players collection
if (playerDeserialized != null)
players.Add(playerDeserialized);
}
// Seeks for player with room prize 10
foreach (var player in players)
{
if (player.RoomPrize == 10)
// Increments players data wins count
player.Wins += 1;
}
// Updates the raw data serializing all players back again
rawData = string.Join("/", Array.ConvertAll(players.ToArray(), (p) => p.Serialize()));
Console.WriteLine(rawData);
Console.ReadLine();
}
}
class Player
{
public int RoomPrize { get; set; }
public int Wins { get; set; }
public static Player Deserialize(string data, char separator = ',')
{
Player player = null;
string[] splittedData = new string[] { };
if (!string.IsNullOrEmpty(data) && (splittedData = data.Split(separator)).Length == 2)
{
int roomPrize = 0, wins = 0;
if (int.TryParse(splittedData[0], out roomPrize) && int.TryParse(splittedData[1], out wins))
{
player = new Player();
player.RoomPrize = roomPrize;
player.Wins = wins;
}
}
return player;
}
public string Serialize()
{
return string.Format("{0},{1}", this.RoomPrize, this.Wins);
}
}
}
It's much more code, but is easier to maintain.

Related

How can I access multi-element List data stored in a public class?

My first question on SO:
I created this public class, so that I can store three elements in a list:
public class myMultiElementList
{
public string Role {get;set;}
public string Country {get;set;}
public int Commonality {get;set;}
}
In my main class, I then created a new list using this process:
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
I've added data to EmployeeRolesCountry and have validated that has 472 lines. However, when I try to retrieve it as below, my ForEach loop only retrieves the final line added to the list, 472 times...
foreach (myMultiElementList tmpClass in EmployeeRolesCountry)
{
string d1Value = tmpClass.Role;
Console.WriteLine(d1Value);
string d2Value = tmpClass.Role;
Console.WriteLine(d2Value);
int d3Value = tmpClass.Commonality;
Console.WriteLine(d3Value);
}
This was the most promising of the potential solutions I found on here, so any pointers greatly appreciated.
EDIT: adding data to EmployeeRolesCountry
/*
Before this starts, data is taken in via a csvReader function and parsed
All of the process below is concerned with two fields in the csv
One is simply the Country. No processing necessary
The other is bio, and this itself needs to be parsed and cleansed several times to take roles out
To keep things making sense, I've taken much of the cleansing out
*/
private void File_upload_Click(object sender, EventArgs e)
{
int pos = 0;
var EmployeeRolesCountry = new List<myMultiElementList>();
var rc1 = new myMultiElementList();
int a = 0;
delimiter = ".";
string token;
foreach (var line in records.Take(100))
{
var fields = line.ToList();
string bio = fields[5];
string country = fields[4];
int role_count = Regex.Matches(bio, delimiter).Count;
a = bio.Length;
for (var i = 0; i < role_count; i++)
{
//here I take first role, by parsing on delimiter, then push back EmployeeRolesCountry with result
pos = bio.IndexOf('.');
if (pos != -1)
{
token = bio.Substring(0, pos);
string original_token = token;
rc1.Role = token.Trim();
rc1.Country = country.Trim();
rc1.Commonality = 1;
EmployeeRolesCountry.Add(rc1);
a = original_token.Length;
bio = bio.Remove(0, a + 1);
}
}
}
}
EDIT:
When grouped by multiple properties, this is how we iterate through the grouped items:
var employeesGroupedByRolwAndCountry = EmployeeRolesCountry.GroupBy(x => new { x.Role, x.Country });
employeesGroupedByRolwAndCountry.ToList().ForEach
(
(countryAndRole) =>
{
Console.WriteLine("Group {0}/{1}", countryAndRole.Key.Country, countryAndRole.Key.Role);
countryAndRole.ToList().ForEach
(
(multiElement) => Console.WriteLine(" : {0}", multiElement.Commonality)
);
}
);
__ ORIGINAL POST __
You are instantiating rc1 only once (outside the loop) and add the same instance to the list.
Please make sure that you do
var rc1 = new myMultiElementList();
inside the loop where you are adding the elements, and not outside.
All references are the same in your case:
var obj = new myObj();
for(i = 0; i < 5; i++)
{
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
now the list has 5 elements, all pointing to the obj (the same instance, the same object in memory), and when you do
obj.Prop1 = "Prop" + 5
you update the same memory address, and all the pointers in the list points to the same instance so, you are not getting 472 copies of the LAST item, but getting the same instance 472 times.
The solution is simple. Create a new instance every time you add to your list:
for(i = 0; i < 5; i++)
{
var obj = new myObj();
obj.Prop1 = "Prop" + i;
list.Add(obj);
}
Hope this helps.

Read lines of data from CSV then display data

I have to read info from a txt file, store it in a manner (array or list), then display the data. Program must include at least one additional class.
I've hit a wall and can't progress.
string, string, double, string
name,badge,salary,position
name,badge,salary,position
name,badge,salary,position
I'm sorry and I know the code below is disastrous but I'm at a loss and am running out of time.
namespace Employees
{
class Program
{
static void Main()
{
IndividualInfo collect = new IndividualInfo();
greeting();
collect.ReadInfo();
next();
for (int i = 0; i < 5; i++)
{
displayInfo(i);
}
exit();
void greeting()
{
Console.WriteLine("\nWelcome to the Software Development Company\n");
}
void next()
{
Console.WriteLine("\n*Press enter key to display information . . . *");
Console.Read();
}
void displayInfo(int i)
{
Console.WriteLine($"\nSoftware Developer {i + 1} Information:");
Console.WriteLine($"\nName:\t\t\t{collect.nameList[i]}");
}
void exit()
{
Console.WriteLine("\n\n*Press enter key to exit . . . *");
Console.Read();
Console.Read();
}
}
}
}
class IndividualInfo
{
public string Name { get; set; }
//public string Badge{ get; set; }
//public string Position{ get; set; }
//public string Salary{ get; set; }
public void ReadInfo()
{
int i = 0;
string inputLine;
string[] eachLine = new string[4];
string[,] info = new string[5, 4]; // 5 developers, 4x info each
StreamReader file = new StreamReader("data.txt");
while ((inputLine = file.ReadLine()) != null)
{
eachLine = inputLine.Split(',');
for (int x = 0; x < 5; x++)
{
eachLine[x] = info[i, x];
x++;
}
i++;
}
string name = info[i, 0];
string badge = info[i, 1];
string position = info[i, 2];
double salary = Double.Parse(info[i, 3]);
}
public List<string> nameList = new List<string>();
}
So far I think I can collect it with a two-dimensional array, but a List(s) would be better. Also, the code I've posted up there won't run because I can't yet figure out a way to get it to display. Which is why I'm here.
using System.IO;
static void Main(string[] args)
{
using(var reader = new StreamReader(#"C:\test.csv"))
{
List<string> listA = new List<string>();
List<string> listB = new List<string>();
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
var values = line.Split(';');
listA.Add(values[0]);
listB.Add(values[1]);
}
}
}
https://www.rfc-editor.org/rfc/rfc4180
or
using Microsoft.VisualBasic.FileIO;
var path = #"C:\Person.csv"; // Habeeb, "Dubai Media City, Dubai"
using (TextFieldParser csvParser = new TextFieldParser(path))
{
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
// Skip the row with the column names
csvParser.ReadLine();
while (!csvParser.EndOfData)
{
// Read current line fields, pointer moves to the next line.
string[] fields = csvParser.ReadFields();
string Name = fields[0];
string Address = fields[1];
}
}
http://codeskaters.blogspot.ae/2015/11/c-easiest-csv-parser-built-in-net.html
or
LINQ way:
var lines = File.ReadAllLines("test.txt").Select(a => a.Split(';'));
var csv = from line in lines
select (from piece in line
select piece);
^^Wrong - Edit by Nick
It appears the original answerer was attempting to populate csv with a 2 dimensional array - an array containing arrays. Each item in the first array contains an array representing that line number with each item in the nested array containing the data for that specific column.
var csv = from line in lines
select (line.Split(',')).ToArray();
This question was fully addressed here:
Reading CSV file and storing values into an array

How to sort data stored in a text file by high score in c#

I am making a quiz game for my computing coursework and I have completed the quiz part of my application and I am currently moving on to my leader board but to do that I need to sort my scores text file which contains the users name, score and time but I am now trying to retrieve these data and display them in a table.
The users' name score and time saves fine into the scores text file but to display these details I first need to order these details by the score.
My test file is organised like this:
username,score,time
userName1,33,12
userName2,-55,33
userName3,34,2
userName4,23,27
userName5,63,72
This is the code that I am currently using but this only works if I have the data in the text file sorted first.
string[] readFile = File.ReadAllLines(file).ToArray();
for (int i = 0; i < 5; i++)
{
string[] userDetails = File.ReadAllLines(file).ToArray();
string username = userDetails[0];
string score = userDetails[1];
// Apply the text of lblUsername1-5 to be what the names
// of the top 5 scorers are in the file.
lblUsername1.Text = userDetails[0].Split(',')[0];
lblUsername2.Text = userDetails[1].Split(',')[0];
lblUsername3.Text = userDetails[2].Split(',')[0];
lblUsername4.Text = userDetails[3].Split(',')[0];
lblUsername5.Text = userDetails[4].Split(',')[0];
// Apply the text of lblScore1-5 to be what the scores
// of the top 5 scorers are in the file.
lblScore1.Text = userDetails[0].Split(',')[1];
lblScore2.Text = userDetails[1].Split(',')[1];
lblScore3.Text = userDetails[2].Split(',')[1];
lblScore4.Text = userDetails[3].Split(',')[1];
lblScore5.Text = userDetails[4].Split(',')[1];
}
So if some one could help me to sort the data in my scores ext file that would be great. Thanks in advance.
You can use linq to sort data from your file
string[][] userDetails = File.ReadAllLines(file).Select(s => s.Split(',')).OrderBy(arr => int.TryParse(arr[1], out int result) ? result : 0)).Take(5).ToArray();
lblUsername1.Text = userDetails[0][0];
lblUsername2.Text = userDetails[1][0];
lblUsername3.Text = userDetails[2][0];
lblUsername4.Text = userDetails[3][0];
lblUsername5.Text = userDetails[4][0];
// Apply the text of lblScore1-5
// to be what the scores of the top 5 scorers are in the file.
lblScore1.Text = userDetails[0][1];
lblScore2.Text = userDetails[1][1];
lblScore3.Text = userDetails[2][1];
lblScore4.Text = userDetails[3][1];
lblScore5.Text = userDetails[4][1];``
You should use objects to manage this. Your class should be a user with properties, se below.
Now you have full control on sorting and managing of your objects
using System.Collections.Generic;
using System.Linq;
public class User
{
public string Name { get; set; }
public int Score { get; set; }
public int Time { get; set; }
}
class Program
{
public static void Main(string[] args)
{
//This you get from file, no need for this in your code
string[] fromFile = new string[5]
{ "userName1,33,12", "userName2,-55,33", "userName3,34,2", "userName4,23,27", "userName5,63,72" };
List<User> users = new List<User>();
foreach (string line in fromFile)
{
string[] splitLine = line.Split(',');
users.Add(new User() { Name = splitLine[0], Score = int.Parse(splitLine[1]), Time = int.Parse(splitLine[2]) });
}
foreach (User oneUser in users.OrderByDescending(x => x.Score))
{
//Here the store to file or what you want to do
}
}
}

Try to convert text file to Excel [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I have text file like this:
VehicleReferenceKey:2365565656
DriverReferenceKey:965454545454
Latitude:30000
**
VehicleReferenceKey:96896A4607A6
DriverReferenceKey:96896A4607A6
Latitude:500
**
VehicleReferenceKey:822F5B18
DriverReferenceKey:822F5B18
Latitude:1000
I try To convert this text file to Excel
first i made an Class as
public class Item
{
public string VehicleReferenceKey;
public string DriverReferenceKey;
public string Latitude;
}
then i read all text file and looping of it as
var lines = File.ReadAllLines(fileName);
for (var i = 0; i < lines.Length; i += 1) {
var line = lines[i];
// Process line
}
but I Can't determine how i can specify the Key and value
for each line , and how tell the sign
**
as it's breaker between each object .Any Help
Try following code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication87
{
class Program
{
const string FILENAME = #"c:\temp\test.txt";
static void Main(string[] args)
{
Item items = new Item(FILENAME);
}
}
public class Item
{
public static List<Item> items = new List<Item>();
public string VehicleReferenceKey;
public string DriverReferenceKey;
public string Latitude;
public Item() { }
public Item(string filenam)
{
StreamReader reader = new StreamReader(filenam);
string line = "";
Item newItem = null;
while ((line = reader.ReadLine()) != null)
{
line = line.Trim();
if (line.Length > 0)
{
string[] rowItems = line.Split(new char[] { ':' });
switch (rowItems[0])
{
case "VehicleReferenceKey" :
newItem = new Item();
items.Add(newItem);
newItem.VehicleReferenceKey = rowItems[1];
break;
case "DriverReferenceKey":
newItem.DriverReferenceKey = rowItems[1];
break;
case "Latitude":
newItem.Latitude = rowItems[1];
break;
}
}
}
}
}
}
Basically it seems the following hold for your file:
The first item takes 3 lines (one for each field)
Every item after the first takes 7 lines (2 empty lines, 1 line containing "**", 1 empty line and then the 3 lines with the field values)
So there's no reason to parse the ** and the empty lines you can just skip those (by looping over 7 lines at a time).
For the seperating key and value you can use the String.Split method.
All in all it would look something like this:
for (var i = 0; i < lines.Length + 2; i += 7)
{
var newItem = new Item(){
VehicleReferenceKey = lines[i].Split(':')[1],
DriverReferenceKey = lines[i+1].Split(':')[1],
Latitude = lines[i+2].Split(':')[1]
}
//do whatever you want with the newItem
}

C# Why can't I implicitly convert type 'string' to 'System.Collections.Generic.List<int>'?

I am trying to figure out how to solve the error as stated in the title, which occurs on the bold line within this snippet:
while (textIn.Peek() != -1)
{
string row = textIn.ReadLine();
string[] columns = row.Split('|');
StudentClass studentList = new StudentClass();
studentList.Name = columns[0];
**studentList.Scores = columns[1];**
students.Add(studentList);
}
The previous line of code loads the names just fine since it is not a List within the class I have created, but "Scores" is within a list, however. What modifications would I need to do? These values are supposed to be displayed within a textbox from a text file upon loading the application.
Here is the class in which "Scores" is in (I have highlighted it):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyNameSpace
{
//set the class to public
public class StudentClass
{
public StudentClass()
{
this.Scores = new List<int>();
}
public StudentClass (string Name, List<int> Scores)
{
this.Name = Name;
this.Scores = Scores;
}
public string Name
{ get;
set;
}
//initializes the scores
**public List<int> Scores
{ get;
set;
}**
public override string ToString()
{
string names = this.Name;
foreach (int myScore in Scores)
{ names += "|" + myScore.ToString();
}
return names;
}
public int GetScoreTotal()
{
int sum = 0;
foreach (int score in Scores)
{ sum += score;
}
return sum;
}
public int GetScoreCount()
{ return Scores.Count;
}
public void addScore(int Score)
{
Scores.Add(Score);
}
}
}
You can't just assign a string containing a sequence of numbers to a property of type List<int>.
You need to split the string into seperate numbers, then parse these substrings to get the integers they represent.
E.g.
var text = "1 2 3 4 5 6";
var numerals = text.Split(' ');
var numbers = numerals.Select(x => int.Parse(x)).ToList();
I.e. in your code replace:
studentList.Scores = columns[1];
with:
studentList.Scores = columns[1].Split(' ').Select(int.Parse).ToList();
(Or your own multi-line, more readable/debugable equivalent.)
You'll need to modify the parameter passed to Split() according to how the scores are formatted in your column.
You'll also need to add using System.Linq; at the top if you don't already have it.
As far as the question goes, how would the compiler ever know how to convert the string to a list, when there could be so many string representations of a list. If it was to do this it would be an incredibly slow operation.
Fix
To fix your code you could replace your loop with this.
while (textIn.Peek() != -1)
{
string row = textIn.ReadLine();
StudentClass studentList = new StudentClass();
int index = row.IndexOf("|");
//checking that there were some scores
if (index < 0) {
studentList.Name = row;
continue;
}
studentList.Name = row.Substring(0, index);
studentList.Scores = row.Substring(index + 1).Split('|').Select(int.Parse).ToList();
students.Add(studentList);
}
There are however a number of problems even with this fix.
For one if you were to add another list delimited by '|' it would become increasingly hard for you to parse using this kind of approach.
I suggest instead that you look at serializing your class(es) with something a little more powerful and generic like Json.Net.
Hope this helps.

Categories