Updating a comma delimited string list in c#
I have a comma delimited string list that looks something like this:
Cat, Animal, 2
Dog, Animal, 3
Luke, Human, 1
Owl, Animal, 0
Now i want to search the list, Find all string elements with animal in them and add one to their number. So in the end of my query the list would look like:
Cat, Animal, 3
Dog, Animal, 4
Luke, Human, 1
Owl, Animal, 1
How can i achieve this functionality? I was thinking of using a LINQ query to get all the entries tha开发者_StackOverflow社区t contain animal and then getting the index of each element in the list, getting all the tokens in each element by using a comma split, parsing the third token into an integer, incrementing by one and rewriting the element at the previously saved index to update the count. This is probably the least efficient method so can anyone suggest a fast, short and sweet solution to this?
Thanks
I would recommend to create a class that represents a row of your list, instead of splitting and searching the strings which is quite inefficient especially if you process the list multiple times, e.g.
public class Creature
{
public string Name { get; set; };
public string Species { get; set; };
public int Count { get; set; };
}
These stored in a list can be accessed more easily. The contents of your strings have to be converted twice: 1st at the start of your program if you read them from a file, and 2nd at the end if you want to store them again.
You can get the results you search for with LINQ like this then:
listOfCreatures.Where(creature => creature.Species == "Animal").ToList();
I would first create a class to hold each item in the list.
public class Creature
{
public string Name { get; set; }
public string Species { get; set; }
public int Count { get; set; }
public Creature(string name, string species, int count)
{
this.Name = name;
this.Species = species;
this.Count = count;
}
public void Add(int numToAdd)
{
this.Count += numToAdd;
}
}
public static class CreatureStorage
{
private static bool isInitialized = false;
private static List<Creature> creatureList = new List<Creature>();
public static List<Creature> CreatureList
{
get {
if (isInitialized == false)
{
Initialize();
}
return creatureList;
}
set { creatureList = value; }
}
public static void Add(string species, int numToAdd)
{
foreach (Creature creature in creatureList)
{
if (creature.Species.Equals(species))
{
creature.Add(numToAdd);
}
}
}
private static void Initialize()
{
// Add code to parse through your initial list whether it's a txt file or just a string in the application
isInitialized = true;
}
Example usage.
public partial class ProcessAnimals : Form
{
public ProcessAnimals()
{
InitializeComponent();
}
private void processAnimals_Click(object sender, EventArgs e)
{
CreatureStorage.Add("Animal", 1);
}
}
Here is some sample code that demostrates what you are describing:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var content = new string[] { "Cat, Animal, 2", "Dog, Animal, 3", "Luke, Human, 1", "Owl, Animal, 0" };
foreach (var item in content)
{
Console.WriteLine(IncrementIfKeywordFound(item, "Animal"));
}
Console.ReadLine();
}
private static string IncrementIfKeywordFound(string data, string keyword)
{
var parts = data.Split(new [] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (parts[1] == keyword) parts[2] = (Convert.ToInt32(parts[2]) + 1).ToString();
return string.Join(", ", parts);
}
}
}
Assuming that this is a List or anything that can be converted to such
for(i = 0;i < yourList.Count; i++)
{
String str = yourList[i];
if(str.Contains("Animal")
{
var parts = string.Split(@',');
parts[2] = Integer.Parse(parts[2]) + 1;
str = String.Join(parts, ",");
}
}
Read once, write only if changes needed.
Using Regular Expressions. Just for kicks, don't do it this way, it's not very flexible nor maintainable.
static void Main(string[] args)
{
string source = @"Cat, Animal, 2
Dog, Animal, 3
Luke, Human, 1
Owl, Animal, 0";
System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(@", Animal, (\d+)");
foreach (string line in source.Split(new string[] { Environment.NewLine },StringSplitOptions.RemoveEmptyEntries))
{
System.Text.RegularExpressions.MatchCollection collection = r.Matches(line);
if (collection.Count == 1)
{
int val = -1;
int.TryParse(collection[0].Groups[1].Value, out val);
Console.WriteLine(line.Replace(val.ToString(), (val + 1).ToString()));
}
else
{
Console.WriteLine(line);
}
}
}
Here is an answer as a single Linq expression:
List<string> source = new List<string>();
source.Add("Cat, Animal, 2");
source.Add("Dog, Animal, 3");
source.Add("Luke, Human, 1");
source.Add("Owl, Animal, 0");
List<string> dest = new List<string>(
source
.Select(s => s.Split(new []{',', ' '}, StringSplitOptions.RemoveEmptyEntries))
.Select(s => { if(s[1] == "Animal") s[2] = (Convert.ToInt32(s[2]) + 1).ToString(); return s; })
.Select(s => String.Join(", ", s))
);
Here would be one sketchy example. Load the CSV into a "table" and just modify it and write back to file.
public static List<string[]> LoadCSV() {
List<string[]> table = new List<string[]>();
// Replace the below with something like File.ReadAllLines(...);
string[] lines = "Cat, Animal, 3\r\nDog, Animal, 4\r\nLuke, Human, 1\r\nOwl, Animal, 1"
.Split(new string[] { "\r\n" }, StringSplitOptions.None);
foreach (string line in lines) {
table.Add(line.Split(new string[] { ", " }, StringSplitOptions.None));
}
return table;
}
static void Main(string[] args) {
List<string[]> items = LoadCSV();
foreach (string[] item in items) {
if (item[2] == "Animal") {
item[2] = (int.Parse(item[1]) + 1).ToString();
}
}
// Write back to file
}
Rather though, you could create a AnimalList class to store a collection of type class 'Animal' that would define properties Animal/Type/Value (or what you wish to call them), and write your own Add/Remove/Save/Load methods.
精彩评论