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 8 months ago.
This post was edited and submitted for review 8 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
I have a Person class and my design needs to have a capacity of up to a million persons. I need to be able to load in memory. I've tried various ways and they work ok for small sets but when the count gets anywhere close to a million it takes too much time and memory. Are there any C# data structures or strategies that are specialized for what I'm trying to do which is store N number (e.g. 1 million) of records for below Class?
Class Person
{
string Id {get;set;}
}
When you say store a million Person records my assumption is that you mean persistent storage and that you're not going to enter them by hand every time you run your app. One way to achieve this goal would be to use one of the various SQLite versions to store the records in a database format. When these records are retrieved with a query, the data can be used to populate a simple data structure like List<Person> or a more complex data structure like DataTable or ViewModel. To keep things simple, this example uses the sqlite-net-pcl NuGet package.
Here, the Person class has been modified with additional tags to let SQLite know how to configure the table:
[Table("Persons")]
class Person
{
[PrimaryKey]
public string Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public override string ToString() => $"{Id} {FirstName} {LastName}";
}
The first snippet creates a temporary database in memory and inserts three records to demo a few basics. To store it on disk, just change databasePath: ":memory:" to a writable path like {MyAppDataFolderPath}\{MyDatabaseName}.db.)
var database = new SQLiteConnection(databasePath: ":memory:");
database.CreateTable<Person>();
database.Insert(new Person { Id = "Admin.1", FirstName = "Tom", LastName = "Hanks" });
database.Insert(new Person { Id = "Admin.2", FirstName = "Tom", LastName = "Holland" });
database.Insert(new Person { Id = "Staff.1", FirstName = "Tom", LastName = "Cruise" });
Here are a few example of retrieving instances of Person from the database and putting them in a List<Person> data structure.
// How many Toms?
int count = database.ExecuteScalar<int>("SELECT COUNT(*) FROM Persons WHERE FirstName='Tom'");
Console.WriteLine($"Found {count} persons named 'Tom'");
// Match a pattern
Console.WriteLine("\nList Admin:");
List<Person> recordset =
database.Query<Person>(
"SELECT * FROM Persons WHERE Id LIKE 'Admin.%'");
foreach (Person record in recordset)
Console.WriteLine(record.ToString());
// Match multiple properties
Console.WriteLine("\nGet ID for Tom Cruise Person");
Person person =
database.Query<Person>(
"SELECT ID FROM Persons WHERE FirstName='Tom' AND LastName='Cruise'"
).First();
Console.WriteLine($"ID is {person.Id}");
As commented, your question could be answered in many different ways and this is just one approach, but it's one that I use in my own production code base which is shared between PC, iOS and Android versions.
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 3 years ago.
Improve this question
I am using a string that comes from a form to find a object in a db with the same name of a variable.
Let's say I want to find a bus station with name "Central" in a db full of bus stations. And if I found one, I want to get the address variable from the "Central" station into a session (for further use). The db is running fine and I can retrieve other stuff from it, but the problem is comparing the two strings.
Session["searchFor"]="Central";
Session["adress"]=null;
var db = new Models.DB();
List<Models.Station> allStations = db.Station.ToList();
foreach (Station station in allStations)
{
if(String.Compare(Session["searchFor"].toString(), station.name) == 0)
{
Session["adress"]=station.adress;
break;
}
}
I have tried every possible compare to method I have found online, but nothing seems to be working.
My DB class looks like this:
public class Station
{
[Key]
public int id { get; set; }
public string name { get; set; }
public string adress { get; set; }
}
The page that write it out looks like this.
From station: #Session["searchFor"] <br />
From station adress: #Session["adress"] <br />
And the result,
enter image description here
the session has not been given a value by the function. I don't know if it's the compare function that does not work, or the line that are supposed to be given the session the value. If I write
if(String.Compare(Session["searchFor"].toString(), station.name) == 0)
{
Session["adress"]="TEST";
break;
}
it does NOT says "From station adress: Test" on the website either.
There is alot of improvements you can make with this code. First off, Session["searchFor"].ToString() is really Object.toString() and it is not doing what you think it is doing, it is not converting the value for the "searchFor" key to a string.
Below is a much improved version that is just common best practices in any coding language and also a couple common patterns in C#. It includes correctly spelling variables and also upper casing Properties in C# classes and dealing with potential case sensitivity of your string comparisons.
Session["searchFor"] = "Central"; //setting Session values for testing
//Session["address"] = null; there is no need for this.
var db = new Models.DB();
List<Models.Station> allStations = db.Station.ToList();
var searchForValue = (string) Session["searchFor"];
foreach (Station station in allStations)
{
if (searchForValue.ToLower() == station.Name.ToLower())
{
Session["address"] = station.Address;
break;
}
}
And here is a version that is very common in C# using LINQ:
//setting Session values for testing
Session["searchFor"] = "Central";
var db = new Models.DB();
List<Models.Station> allStations = db.Station.ToList();
var searchForValue = (string) Session["searchFor"];
var station = allStations.FirstOrDefault(x => x.Name.ToLower() == searchForValue.ToLower());
if (station != null)
{
Session["address"] = station.Address;
}
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 7 years ago.
Improve this question
I want to generate a random number from first list (list of Object) and put it in the second list to get a random connection id to make connection between the original id and the random id how I can get the item from the first list by index and of which type I have to cast it
public class OneHub :Hub
{
static List<UserId> ConnectedUser = new List<UserId>();
static List<MessageDetail> CurrentMessage = new List<MessageDetail>();
static List<ConnectionsId> Connection = new List<ConnectionsId>();
public void Connect(string id)
{
if (ConnectedUser.Count(x => x.ConnectionId == id) == 0)
{
ConnectedUser.Add(new UserId { ConnectionId = id });
if (ConnectedUser.Count != 0 || ConnectedUser.Count != 1)
{
Random r = new Random();
int x = r.Next(0,ConnectedUser.Count);
(object)ConnectedUser.item[x];
Connection.Add(new ConnectionsId {ConnectionId=id,ConnectionId2= })
}}}
First off, you're going to need to make sure that the ConnectedUser that you randomly get is not the same user you are linking to, before you add that connection, or you're going to find further issues.
For ConnectedUser, you can get the index by simply using ConnectedUser[x]. (I suggest making your lists plural so it's obvious that they're collections.)
You need to assign that connected user to a new object.
Something like
UserID linkedUser = ConnectedUser[x];
This way, you can reference linkedUser.ConnectionId in your connection addition.
Alternately, you could just use:
Connection.Add(new ConnectionsId { ConnectionId = id, ConnectionId2 = ConnectedUser[x].ConnectionId };
This random setup, though, does have a strong potential for having several people ending up not linked to anyone. Additionally, your line that states:
if (ConnectedUser.Count != 0 ...
is redundant. You just added a user to that list. It should never be of size 0.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
I wanted to suggestion on the best practices in coding for a real scenario.
The scenario is this:
I have a list of 100 items.
public CustomObject
{
public int id {get;set;}
public string name {get;set;}
}
List<CustomObject> lstObj = new List<CustomObject>();
lstobj can have sample values such as
A,1 B,2 C,3 C,4 C,5 etc
Now, I have a tabular data as follows:
Low High
A 10 100
Z 89 100
while looping through the list, I need to check against this data, and if suppose A value is more than 100 I need to put it to some xml file.
Now, my approach is
a) I will be putting this master data into a list formatfor eg:
public class CheckValues
{
public string name { get;set;}
public int lowerlimit { get;set;}
public int upperlimit {get;set;}
}
and populating the list with the data like
Low High
A 10 100
Z 89 100
b) using a foreach loop , I will be looping the lstobj items and within this each iteration , I would be once again iterating the list to check if the item exists and if it exists whats the value (max or min)
Basically I am using the two forloops. Is it approach acceptable or is there any best practices/suggestions to improve the practice advisable on this?
If the number of entries in each list is small, your solution may be an acceptable solution, but if either of them is large, this is one of the worst ways to do it. A list means linear lookup (n*m). If you use some other container or if you sort first, you can achieve far better (n*1) performance.
I would recommend removing name:
public class CheckValues
{
public int lowerlimit {get;set;}
public int upperlimit {get;set;}
}
Then use Dictionary<string, CheckValues> to look up the limits
Dictionary<string, CheckValues> limits /* = ... */;
foreach(var item in data) // Just one foreach
{
var limit = limits[item]; // Looking up the limit is O(1) instead of O(n)
}
or you can use LINQ
List<CustomObject> lstObj = new List<CustomObject>(){ new CustomObject(){ id = 1, name = "name1" }, new CustomObject() { id = 2, name = "name2" } };
then you can select the highest value
CustomObject highestvalue = lstObj.OrderByDescending(x => x.id).FirstOrDefault();
or the lowest value
CustomObject lowestvalue = lstObj.OrderBy(x => x.id).FirstOrDefault();
you can also find data ids that's greater than 100
var objgreaterthan100 = lstObj.FindAll(x => x.id > 100);
then you can iterate to your objgreaterthan100 then put in XML.
foreach (var CustomObject in objgreaterthan100)
{
//your code for saving in xml
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
So I have a .CSV file which has possibly several millions, maybe even billions lines of data. The data is in the format below:
1,,5,6,7,82,4,6
1,4,4,5,6,33,4,
2,6,3,,6,32,6,7
,,,2,5,45,,6
,4,5,6,,33,5,6
What I am trying to achieve is this: Lets assume each line of data is an "event". Lets call it that. Now lets say an user says, show me all events where the 6th value is 33. You can see above that the 6th data element is a 2 digit number and the user can say show me all events where the 6th data element is 33 and the output would be:
1,4,4,5,6,33,4,
,4,5,6,,33,5,6
Also, as you can see. The data can have blanks or holes where data is missing. I don't need help reading a .CSV file or anything. I just cant wrap my mind around how I would access the 6th data element. Also, I would prefer if this output is represented in a collection of some sort maybe. I'm new to C# so I don't have much knowledge about the inbuilt classes. Any help will be appreciated!
I suggest instead of using term "event" to call this data structure more customarily as "rows and columns" and use C# Split() function to create 2d-array (string[,] or int[,]), where each element is conveniently accessible by its row/column index, and to apply whatever business logic to those elements.
Possible implementation of the CSV file reader (by line, with each line stored in the List<string> listRows) is shown below (re: Reading CSV file and storing values into an array)
using System.IO;
static void Main(string[] args)
{
var reader = new StreamReader(File.OpenRead(#"C:\YouFile.csv"));
List<string> listRows= new List<string>();
while (!reader.EndOfStream)
{
listRows.Add(reader.ReadLine());
}
}
Then apply Split(',') function to each row (stored in listRows) to compose a 2d-array string[,] and use int.TryParse() method to convert it to type int (optional, upon necessity).
Alternatively, this could be implemented by using LINQ Library, which is not recommended because of unnecessary extension of the technology surface area, plus possible performance degradation (LINQ solution expected to be slower than suggested direct processing).
Hope this may help.
Using Linq it is pretty easy to achieve. I'm posting as sample from LinqPad and providing output. All you need to do is to replace 33 with a parameter:
void Main()
{
string csvFile = #"C:\Temp\TestData.csv";
string[] lines = File.ReadAllLines(csvFile);
var values = lines.Select(s => new { myRow = s.Split(',')});
//and here is your collection representing results
List<string[]> results = new List<string[]>();
foreach (var value in values)
{
if(value.Values.Contains("33")){
results.Add(value.myRow);
}
}
results.Dump();
}
Output:
or if you want you can have it all in one shot by doing this
string csvFile = #"C:\Temp\TestData.csv";
string[] lines = File.ReadAllLines(csvFile);
var values = lines.Select(s =>
new {Position =Array.FindIndex(s.Split(','),a=>a.Contains("33"))+1
,myRow = s.Split(',')
});
so the final product will have both - the position of your search (33) and the complete string[] of items.
Create a class EventEntity. In this class create a List<int> with a constructor that initializes the list. Here is a class example:
public class EventEntity
{
public EventEntity()
{
EventList = new List<int>();
}
public List<int> EventList { get; set; }
}
From there loop through each row of data. Example:
public class EventEntityRepo
{
public EventEntity GetEventEntityByCsvDataRow(String[] csvRow)
{
EventEntity events = new EventEntity();
foreach (String csvCell in csvRow)
{
int eventId = -1;
if(csvCell != null && csvCell != String.Empty)
{
try
{
eventId = Convert.ToInt32(csvCell.Trim());
}
catch (Exception ex)
{
//failed to parse int
}
}
events.EventList.Add(eventId); //if an empty item, insert -1
}
return events;
}
}
Then you can reference the items whenever you want.
eventEntityList = GetEventEntityByCsvDataRow(csvDataRow);
eventEntitySixthElement = eventEntityList[5];
So your questions is how to access the 6th data element. It's not too hard if you have right data structure representing your csv.
Basically this csv document in abstract term can be described as IEnumerable<IEnumerable<String>>, or, maybe, IEnumerable<IEnumerable<int?>>. Having implemented csv parsing logic, you will access the 6th elements by executin:
var csvRepresenation = ParseCsv(#"D:/file.csv");
var element = csvRepresentation.ElementAt(6);
if (element == "6")
{
// do smth
}
With this aproach you will also be able to execute Linq statements on it.
Now the question is how you will implement the ParseCsv():
public IEnumerable<IEnumerable<String>> ParseCsv(string path)
{
return File.ReadAllLines(path).Select(row => row.Split(','));
}