Table of strings in C# - c#

Is there a way of creating a table with each cell containing a string in C# ?
The closest thing I found is multidimensional arrays string[,] names;, but it seems like its length needs to be defined which is a problem to me.
Here is what my code looks like :
string[] namePost;
int[] numbPage;
string post="";
string newPost;
int i=0;
int j=0;
foreach (var line in File.ReadLines(path).Where(line => regex1.Match(line).Success))
{
newPost = regex1.Match(line).Groups[1].Value;
if (String.Compare(newPost, post) == 0)
{
j = j + 1;
}
else
{
namePost[i] = post;
numbPage[i] = j;
post = newPost;
j = 1;
i = i + 1;
}
}
Each instance of the for writes the name of the new "post" in a cell of namePost. In the end, the namePost table stores the name of all the posts that are different from one another.
What is the best way to achieve that ?

If you are simply trying to store the posts, you can use the List class from the System.Collections.Generic namespace:
using System.Collections.Generic;
List<String> namePost = new List<String>();
Then, instead of namePost[i] = post;, use
namePost.Add(post);

DataTable
https://msdn.microsoft.com/en-us/library/system.data.datatable(v=vs.110).aspx
Use this, no need to define length at all.
Useful guide and examples:
http://www.dotnetperls.com/datatable

You can just use a
var table = new List<List<string>>();
This would give you a dynamic 2D table of strings.

This will give you all your unique posts. If you want the result as a list you can just do a
.ToList ()
with the result.
static IEnumerable<string> AllPosts(Regex regex, string filePath)
{
return File.ReadLines (filePath)
.Where (line => regex.Match (line).Success)
.Select (line => regex.Match (line).Groups [1].Value)
.Distinct ();
}

Related

How to turn a string into a 2d string array

as the title suggests, I am looking for guidance in how to turn a string (csvData) into a 2D string array by splitting it two times with ';' and ',' respectivly.
Currently I am at the stage where I am able to split it once into rows and turn it into an array, but I cannot figure out how to instead create a 2D array where the columns divided by ',' are also separate.
string[] Sep = csvData.Split(';').Select(csvData => csvData.Replace(" ","")).Where(csvData => !string.IsNullOrEmpty(csvData)).ToArray();
I have tried various things like :
string[,] Sep = csvData.Split(';',',').Select(csvData => csvData.Replace(" ","")).Where(csvData => !string.IsNullOrEmpty(csvData)).ToArray();
naivly thinking that c# would understand what I tried to achieve, but since I am here it's obvious that I got the error that "cannot implicitly convert type string[] to string [*,*]"
Note that I have not coded for a while, so if my thinking is completely wrong and you do not understand what I am trying to convey with this question, I apologize in advance.
Thanks!
In a strongly-typed language like C#, the compiler makes no assumptions about what you intend to do with your data. You must make your intent explicit through your code. Something like this should work:
string csvData = "A,B;C,D";
string[][] sep = csvData.Split(';') // Returns string[] {"A,B","C,D"}
.Select(str => str.Split(',')) // Returns IEnumerable<string[]> {{"A","B"},{"C","D"}}
.ToArray(); // Returns string[][] {{"A","B"},{"C","D"}}
Rows are separated by semicolon, columns by comma?
Splitting by ';' gives you an array of rows. Split a row by ',' gives you an array of values.
If your data has a consistent schema, as in each csv you process has the same columns, you could define a class to represent the entity to make the data easier to with with.
Let's say it's customer data:
John,Smith,8675309,johnsmith#gmail.com;
You could make a class with those properties:
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
}
Then:
var rows = csvdata.Split(';');
List<Customer> customers = new();
foreach(var row in rows)
{
var customer = row.Split(',');
customers.Add(new()
{
FirstName = row[0],
LastName = row[1],
Phone = row[2],
Email = row[3]
});
}
Now you have a list of customers to do whatever it is you do with customers.
Here is an answer to present a few alternative ideas and things you can do with C# - more for educational/academic purposes than anything else. These days to consume a CSV we'd use a CSV library
If your data is definitely regularly formed you can get away with just one Split. The following code splits on either char to make one long array. It then stands to reason that every 4 elements is a new customer, the data of the customer being given by n+0, n+1, n+2 and n+3. Because we know how many data items we will consume, dividing it by 4 gives us the number of customers so we can presize our 2D array
var bits = data.Split(';',',');
var twoD = new string[bits.Length/4,4];
for(int x = 0; x < bits.Length; x+=4){
twoD[x/4,0] = bits[x+0];
twoD[x/4,1] = bits[x+1];
twoD[x/4,2] = bits[x+2];
twoD[x/4,3] = bits[x+3];
}
I don't think I'd use 2D arrays though - and I commend the other answer advising to create a class to hold the related data; you can use this same technique
var custs = new List<Customer>();
for(int x = 0; x < bits.Length;){
custs.Add(new()
{
FirstName = bits[x++],
LastName = bits[x++],
Phone = bits[x++],
Email = bits[x++]
});
}
Here we aren't incrementing x in the loop header; every time a bit of info is assigned x is bumped up by 1 in the loop body. We could have kept the same approach as before, jumping it by 4 - just demoing another approach that lends itself well here.
I mentioned that these days we probably wouldn't really read a csv manually and split ourselves - what if the data contains a comma, or a semicolon - it wrecks the file structure
There are a boatload of libraries that read CSV files, CsvHelper is a popular one, and you'd use it like:
using var reader = new StreamReader("path\\to\\file.csv");
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture)
var custs = csv.GetRecords<Customer>().ToList();
...
Your file would have a header line with column names that match your property names in c#. If it doesn't then you can use attributes on the properties to tell CsvH what column should be mapped to what property - https://joshclose.github.io/CsvHelper/getting-started/
Here's the simplest way I know to produce a 2d array by splitting a string.
string csvData = "A,B,C;D,E,F,G";
var temporary =
csvData
.Split(';')
.SelectMany((xs, i) => xs.Split(',').Select((x, j) => new { x, i, j }))
.ToArray();
int max_i = temporary.Max(x => x.i);
int max_j = temporary.Max(x => x.j);
string[,] array = new string[max_i + 1, max_j + 1];
foreach (var t in temporary)
{
array[t.i, t.j] = t.x;
}
I purposely chose csvData to be missing a value.
temporary is this:
And the final array is this:

C# Split - Split on list dont return all the wanted strings

I'm fairly new to C#, and i've come across a problem trying to split on list elements.
I have a resource file containing string properties as such:
ResourceFile
ResourceFile
I've collected them in a List as:
public List<String> RawNewsList1 = new List<String>()
{
{Resource.NewsContentAndroid1},
{Resource.NewsMetaAndroid1},
};
I'm trying to split on the semicolons but only get results from my second list item.
My split look like this:
public void FilterRawNews()
{
String[] seperator = { ";;;" };
String[] filteredList1 = { "" };
for (int i = 0; i < RawNewsList1.Count; i++) {
filteredList1 = RawNewsList1[i].Split(seperator, 5,
StringSplitOptions.RemoveEmptyEntries);
}
foreach (String s in filteredList1)
{
Console.WriteLine(s);
}
}
Its only prints:
110
2.8
02-07-2020
What am i doing wrong?
Thanks in advance!
The filteredList1 variable is first filled with data from your the first resource, then at the next loop the variable's content is replaced with the data coming from the second resource.
You can use a List<string> instead that has the AddRange method to continuosly add elements to the list
List<string> filteredList1 = new List<string>();
for (int i = 0; i < RawNewsList1.Count; i++) {
filteredList1.AddRange(RawNewsList1[i].Split(seperator, 5,StringSplitOptions.RemoveEmptyEntries));
}
From this we could simplify the code to one-liner with
filteredList = RawNewsList1.SelectMany(a => a.Split(seperator,5, StringSplitOptions.RemoveEmptyEntries)).ToList();
So, what's happen in that single line? That syntax is used when you work with objects that can be treated as a sequence of data. In this context your array RawNewsList1 is a sequence of data and we can use the IEnumerable extensions brought to us by using the Linq namespace. The SelectMany extension requires a lambda expression ( a => ....) that is used to produce the instructions where each element of the sequence (a) is passed to an expression that returns another sequence of data (the array returned by Split). The sequence returned is accumulated to the sequence produced by the next elements from the original RasNewsList1. Finally the accumulated sequence is materialized with the call to ToList()
You are overwriting filteredList1 in each iteration.
That is why you only get the last result.
Just declare filteredList1 as a list and and use AddRange().
Edit: or use LINQ:
var raw = new List<string>() { "111;;;222", "333;;;444" };
String[] seperator = { ";;;" };
var filterlist1 = raw.SelectMany(r => r.Split(seperator, 5, StringSplitOptions.RemoveEmptyEntries)).ToList();

C# - Nested Array/Data structures

Recently, I have been getting into C# (ASP.NET) and moving on from PHP. I want to achieve something like this:
mainArray (
array 1 (
'name' => 'example'
),
array 2 (
'name' => 'example2'
)
);
I know that you can use an Array in C# however, you must indicate the length of the Array before doing so which is where the problem is.
I want to loop through a Database in a Class function which returns an Array of all the columns, ie:
id, username, email.
I have tried:
public Array search_bustype(string match, string forthat)
{
db = new rkdb_07022016Entities2();
var tbl = (from c in db.tblbus_business select c).ToArray();
List<string> List = new List<string>();
int i = 0;
foreach (var toCheck in tbl)
{
if (toCheck.BusType.ToString() == match)
{
if (forthat == "Name")
{
List.Add(toCheck.Name);
}
if (forthat == "Address")
{
}
}
i++;
}
return List.ToArray();
}
But as you can see, I am having to only return the single column because the List is not multidimensional (can't be nested).
What can I use to solve this issue? I have looked at some links:
C# Arrays
StackOverflow post
But these again are an issue for my structure since I don't know how many index's I need in the Array when declaring it - The Database grows everyday.
Thanks in advance.
Try something like this. First, define a class for your business model.
public class Person
{
public string Name {get;set;}
public string Address {get;set;}
}
Then use a generic list instead of a string list.
public Person[] search_bustype(string match, string forthat)
{
var db = new rkdb_07022016Entities2();
List<Person> personList = new List<Person>();
foreach (var toCheck in db.tblbus_business.Where(b => b.BusType.ToString() == match))
{
var model = new Person { Name = toCheck.Name, Address = toCheck.Address };
personList.Add(model);
}
return personList.ToArray();
}
I'm not sure what you are trying to do with the forthat variable.
You can use a list of lists
IList<IList<string>> multiList;

Dynamically Generate Codes in C#

I have a list of Enums like the following:
public enum Evaluation : int
{
//Section 1
S1_1_1 = 579,
S1_1_2 = 584,
S1_1_3 = 589,
S1_1_4 = 594,
S1_1_5 = 599,
S1_1_6 = 604,
//Section 2
S1_2_1 = 610,
S1_2_2 = 615,
S1_2_3 = 620,
S1_2_4 = 625,
S1_2_5 = 630,
};
I want to iterate each section and use the values dynamically
int S1Count = 6;
for (int i = 1; i <= S1Count; i++)
{
VoteCount += string.IsNullOrEmpty(this.GetEvaluationValue(FormID, Evaluation.S1_1_ + i)) ? 0 : 1;
}
How can I achieve that? Thanks.
Sorry, my mistake. I tried to get the value from the database by using enum values which are IDs and I have to calculate counts, average for each section.
You can use Enum.Parse to do what you want I think though I don't reccomend it.
To use enum.Parse you'd just need to do something like:
Enum.Parse(typeof(Evaluation), String.Format("S1_1_{0}",i));
This does point at you using some dodgy methodology though. As I said in comments above you would be better off with a data structure allowing you to have sections and their contents easily differentiated. You can do this with either custom classes or maybe just a dictionary of Lists of ints...
Dictionary<int, List<int>> SectionContents;
and use it like:
foreach(int id in SectionContents[sectionNumber])
{
VoteCount += string.IsNullOrEmpty(this.GetEvaluationValue(FormID, id)) ? 0 : 1;
}
(I don't vouch for what's in the foreach, I'm just demonstrating how a dictionary of a list of ints could work).
Creating the Dictionary is easy enough and doesn't require enums. And if this is database stuff could easily be generated through a database query to get the IDs and what sections they are in and then create the data structure.
This will do it
public class Program
{
public static void Main()
{
foreach (FieldInfo fInfo in typeof(Evaluation).GetFields(BindingFlags.Public | BindingFlags.Static))
{
Console.WriteLine("Evaluation." + fInfo.Name);
}
Console.ReadLine();
}
}

Method to check array list containing specific string

I have an ArrayList that import records from a database.
Is there any method to check whether the arrayList contains schname that i want to match to another list which is an api?
List<PrimaryClass> primaryList = new List<PrimaryClass>(e.Result);
PrimaryClass sc = new PrimaryClass();
foreach (string item in str)
{
for (int a = 0; a <= e.Result.Count - 1; a++)
{
string schname = e.Result.ElementAt(a).PrimarySchool;
string tophonour = e.Result.ElementAt(a).TopHonour;
string cca = e.Result.ElementAt(a).Cca;
string topstudent = e.Result.ElementAt(a).TopStudent;
string topaggregate = e.Result.ElementAt(a).TopAggregate;
string topimage = e.Result.ElementAt(a).TopImage;
if (item.Contains(schname))
{
}
}
}
This is what I have come up with so far, kindly correct any errors that I might have committed. Thanks.
How about ArrayList.Contains?
Try this
foreach( string row in arrayList){
if(row.contains(searchString)){
//put your code here.
}
}
Okay, now you've shown that it's actually a List<T>, it should be easy with LINQ:
if (primaryList.Any(x => item.Contains(x.PrimarySchool))
Note that you should really consider using foreach instead of a for loop to iterate over a list, unless you definitely need the index... and if you're dealing with a list, using the indexer is simpler than calling ElementAt.
// check all types
var containsAnyMatch = arrayList.Cast<object>().Any(arg => arg.ToString() == searchText);
// check strings only
var containsStringMatch = arrayList.OfType<string>().Any(arg => arg == searchText);

Categories