Naming a variable from a text file - c#

I'm making a program in C# that uses mathematical sets of numbers. I've defined the class Conjunto (which means "set" in spanish). Conjunto has an ArrayList that contains all the numbers of the set. It also has a string called "ID" which is pretty much what it sounds; the name of an instance of Conjunto.
The program have methods that applies the operations of union, intersection, etc, between the sets.
Everything was fine, but now i've a text file with sentences like:
A={1,2,3}
B={2,4,5}
A intersection B
B union A
And so on. The thing is, i don't know how many sets the text file contains, and i don't know how to name the variables after those sentences. For example, name an instance of Conjunto A, and name another instance B.
Sorry for the grammar, english is not my native language.
Thanks!

It's pretty complicated to create varaibles dynamically, and pretty useless unless you have some already existing code that expects certain variables.
Use a Dictionary<string, Conjunto> to hold your instances of the class. That way you can access them by name.

First off, If you don't target lower version than .Net 2.0 use List instead of ArrayList. If I were you I wouldn't reinvent the wheel. Use HashSet or SortedSet to store the numbers and then you can use defined union and intersection.
Secondly, what is your goal? Do want to have just the output set after all operations? Do you want to read and store all actions and them process it on some event?

First of all, your program is taken from bad side. I would advice to start making new one. One of ways to name "variables" dynamicaly is by making class objects and editing their properties.
This is what I made as a starting platform:
First af all I have crated a class called set
class set
{
public string ID { get; set; }
public List<int> numbers { get; set; }
}
Then I have made the code to sort whole textfile into list of those classes:
List<set> Sets = new List<set>();
string textfile = "your text file";
char[] spliter = new char[] { ',' }; //switch that , to whatever you want but this will split whole textfile into fragments of sets
List<string> files = textfile.Split(spliter).ToList<string>();
int i = 1;
foreach (string file in files)
{
set set = new set();
set.ID = i.ToString();
char[] secondspliter = new char[] { ',' }; //switch that , to whatever you want but this will split one set into lone numbers
List<string> data = textfile.Split(secondspliter).ToList<string>();
foreach (string number in data)
{
bool success = Int32.TryParse(number, out int outcome);
if (success)
{
set.numbers.Add(outcome);
}
}
i++;
Sets.Add(set);
}
Hope it helps someone.

Related

How to access individual fields within struct array

I'm trying to complete an assignment and I'm having trouble with the following (I have worked on this for the last 12 hours). Please help.
I have opened a file, saved the file into an struct array. Can access each element of the struct but don't know how I can access each individual field. i.e
Struct
//struct to hold the hand values
public struct CurrentHand
{
public char cardSuit;
public int cardValue;
}
I need to extract the cardValue into an array or variables so I can evaluate each record i.e. is the hand a pair or two pair etc. I have no idea how to do this. From what I have found its not possible to access each field, is this true?
//Open file and load data into array
public static void LoadHandData(CurrentHand[] handData, string fileName)
{
string input = ""; //temporary variable to hold one line of data
string[] cardData; //temporary array to hold data split from input
//Open the file and read the contents
StreamReader readHand = new StreamReader(fileName);
input = readHand.ReadLine(); //one record
cardData = input.Split(' '); //split record into fields
for (int counter = 0; counter < handData.Length; counter++)
{
handData[counter].cardSuit = Convert.ToChar(cardData[counter *2]);
handData[counter].cardValue = Convert.ToInt16(cardData[counter *2 +1]);
}
readHand.Close();
}
To obtain an array containing the values of the cards you hold in your hand, you can do:
var values = handData.Select(x=>x.cardValue).ToArray();
var seeds = handData.Select(x=>x.cardSuit).ToArray();
By the way, your struct should be called Card or something like that, since an Hand is supposed to be a collection of cards. The name you gave to it is just confusing and makes your code less readeable.
Your problem is not clear to me. anyway you can access invidual fields using .
try this...
CurrentHand.cardValue
using above you can get and set value for CurrentHand structure.

Comparing strings multiple times

I'm generating random scripts, but I have to guarantee that each new one is unique (hasn't been repeated before). So basically each script that has already been generated gets compared against every new script.
Instead of just using normal string compare, I'm thinking there must be a way to hash each new script so that comparison will be faster.
Any ideas on how to hash strings to make multiple comparisons faster?
One way is to use a HashSet<String>
The HashSetclass provides high performance set operations. A set is
a collection that contains no duplicate elements, and whose elements
are in no particular order.
HashSet<string> scripts = new HashSet<string>();
string generated_script = "some_text";
if (!scripts.Contains(generated_script)) // is HashSet<String> dont contains your string already then you can add it
{
scripts.Add(generated_script);
}
Also, You can check for existence of duplicate items in the array.
But this may not be very efficient as compared to HashSet<String>
string[] array = new[] {"demo", "demo", "demo"};
string compareWith = "demo";
int duplicates_count = array.GroupBy(x => x).Count(g => g.Count() > 1);
Use HashSet like below
string uniqueCode= "ABC";
string uniqueCode1 = "XYZ";
string uniqueCode2 = "ABC";
HashSet<string> uniqueList = new HashSet<string>();
uniqueList.Add(uniqueCode);
uniqueList.Add(uniqueCode1);
uniqueList.Add(uniqueCode2);
If you see the Count of uniqueList you will 2. so ABC will not be there two times.
You could use a HashSet. a hash-set is guaranteed to never contain duplicates
Store the script along with its hash:
class ScriptData
{
public ScriptData(string script)
{
this.ScriptHash=script.GetHashCode();
this.Script=script;
}
public int ScriptHash{get;private set;}
public string Script{get;private set;}
}
Then, whenever you need to check if your new random script is unique just take the hash code of the new script and seach all your ScriptData instances for any with the same hash code. If you dont find any you know your new random script is unique. If you do find some then they may be the same and you'll have to compare the actual text of the scripts in order to see if they're identical.
You can store each generated string in a HashSet.
For each new string you will call the method Contains which runs in O(1) complexity. This is an easy way to decide if the new generated string was generated before.

How to organize a large number of file/directory path constants

I have a static class where I keep a large number of relative paths that are used in different places in my application. It looks like that:
static class FilePathConstants
{
public const string FirstDirectory = "First";
public const string FirstSecondDirectory = "First/Second";
public const string FirstSecondThirdFileA = "First/Second/Third/FileA";
public const string FirstSecondFourthFileB = "First/Second/Fourth/FileB";
... nearly 100 of similar members
}
All of them are relative to some parent directory, location of which I know only during the program run. I need to keep them all together because it allows me to easily control what files are used by my application and change their locations from time to time.
However even though they are organized in alphabetic order and its easy to find a certain path, I need to be able to change some of them depending on some setting. Lets say, there is a setting 'bool SettingA' and when I turn it on, I have to do modify some of the paths to use a different directory or a different file name.
The problem is that now I can't use constants, I have to rewrite my code to properties or methods so that I can change file paths at runtime. And here where my code becomes much bigger in size and the strict order now looks ugly. Is there a way I can group them, so that it will not confuse anybody who uses this code? I can't break them into a separate classes because it is difficult to remember in what class what constant you may keep. For now I'm grouping them by regions, but I have a bad feeling that keeping more than one hundred of properties in one class is wrong.
Edit:
All directories and files that I declare in FilePathConstants are used in a large number of places in application (each path can be used multiple times, taking into account the fact that there is more then one hundred of paths - this is a large number). I would like to keep the interface of this class the same or with minimum changes to other classes that use them.
maybe you could use rowstructs
Use something like "index" file to store the directory paths and load it in runtime.
const string indexFilePath = #"C:\dirlist.txt";
IEnumerable<string> paths = File.ReadAllLines(indexFilePath);
Update
I would like to suggest using indirection - "mapper" class.
Here is how it should look like.
public enum FileSystemElement
{
FirstDirectory,
FirstSecondDirectory,
FirstSecondThirdFileA,
FirstSecondFourthFileB
}
public class FileSystemMapper
{
private readonly string _rootDirectory;
private readonly Dictionary<FileSystemElement, string> _fileElements;
public FileSystemMapper(string rootDirectory, string fileName)
{
_rootDirectory = rootDirectory;
string[] lines = File.ReadAllLines(fileName);
_fileElements = lines.Select(ParsePair).ToDictionary(pair => pair.Key, pair => pair.Value);
}
public string GetPath(FileSystemElement element)
{
string relativePath;
if (!_fileElements.TryGetValue(element, out relativePath))
{
throw new InvalidOperationException("Element not found");
}
string resultPath = Path.Combine(_rootDirectory, relativePath);
return resultPath;
}
private static KeyValuePair<FileSystemElement, string> ParsePair(string line)
{
const string separator = "|";
// File element alias | Path
if (string.IsNullOrEmpty(line))
throw new ArgumentException("Null or empty line", "line");
string[] components = line.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries);
if (components.Length != 2)
throw new ArgumentException("Line has invalid format", "line");
FileSystemElement element;
bool parseResult = FileSystemElement.TryParse(components[0], out element);
if (!parseResult)
throw new ArgumentException("Invalid element name", "line");
string path = components[1]; // for clarity
return new KeyValuePair<FileSystemElement, string>(element, path);
}
Client example:
FileSystemMapper fileSystemMapper = new FileSystemMapper(#"C:\root", #"C:\dirs.txt");
string firstDirectory = fileSystemMapper.GetPath(FileSystemElement.FirstDirectory);
string secondDirectory = fileSystemMapper.GetPath(FileSystemElement.FirstSecondDirectory);
string secondThirdFile = fileSystemMapper.GetPath(FileSystemElement.FirstSecondThirdFileA);
Index file format: <Element name>|<Path><New Line>
Example:
FirstDirectory|First
FirstSecondDirectory|First\Second
FirstSecondThirdFileA|First\Second\Third\FileA
FirstSecondFourthFileB|First\Second\Fourth\FileB
can you not use your projects Properties.Settings? it's stored in the .config file so can be edited after deployment
or just dont make them const, then you can edit them at runtime bu they revert to the original setting on next run.
or dont make the calss static and create an instance each time you use it, then change whats needed and discard the instance when finished.

Importing data files using generic class definitions

I am trying to import a file with multiple record definition in it. Each one can also have a header record so I thought I would define a definition interface like so.
public interface IRecordDefinition<T>
{
bool Matches(string row);
T MapRow(string row);
bool AreRecordsNested { get; }
GenericLoadClass ToGenericLoad(T input);
}
I then created a concrete implementation for a class.
public class TestDefinition : IRecordDefinition<Test>
{
public bool Matches(string row)
{
return row.Split('\t')[0] == "1";
}
public Test MapColumns(string[] columns)
{
return new Test {val = columns[0].parseDate("ddmmYYYY")};
}
public bool AreRecordsNested
{
get { return true; }
}
public GenericLoadClass ToGenericLoad(Test input)
{
return new GenericLoadClass {Value = input.val};
}
}
However for each File Definition I need to store a list of the record definitions so I can then loop through each line in the file and process it accordingly.
Firstly am I on the right track
or is there a better way to do it?
I would split this process into two pieces.
First, a specific process to split the file with multiple types into multiple files. If the files are fixed width, I have had a lot of luck with regular expressions. For example, assume the following is a text file with three different record types.
TE20110223 A 1
RE20110223 BB 2
CE20110223 CCC 3
You can see there is a pattern here, hopefully the person who decided to put all the record types in the same file gave you a way to identify those types. In the case above you would define three regular expressions.
string pattern1 = #"^TE(?<DATE>[0-9]{8})(?<NEXT1>.{2})(?<NEXT2>.{2})";
string pattern2 = #"^RE(?<DATE>[0-9]{8})(?<NEXT1>.{3})(?<NEXT2>.{2})";
string pattern3 = #"^CE(?<DATE>[0-9]{8})(?<NEXT1>.{4})(?<NEXT2>.{2})";
Regex Regex1 = new Regex(pattern1);
Regex Regex2 = new Regex(pattern2);
Regex Regex3 = new Regex(pattern3);
StringBuilder FirstStringBuilder = new StringBuilder();
StringBuilder SecondStringBuilder = new StringBuilder();
StringBuilder ThirdStringBuilder = new StringBuilder();
string Line = "";
Match LineMatch;
FileInfo myFile = new FileInfo("yourFile.txt");
using (StreamReader s = new StreamReader(f.FullName))
{
while (s.Peek() != -1)
{
Line = s.ReadLine();
LineMatch = Regex1.Match(Line);
if (LineMatch.Success)
{
//Write this line to a new file
}
LineMatch = Regex2.Match(Line);
if (LineMatch.Success)
{
//Write this line to a new file
}
LineMatch = Regex3.Match(Line);
if (LineMatch.Success)
{
//Write this line to a new file
}
}
}
Next, take the split files and run them through a generic process, that you most likely already have, to import them. This works well because when the process inevitably fails, you can narrow it to the single record type that is failing and not impact all the record types. Archive the main text file along with the split files and your life will be much easier as well.
Dealing with these kinds of transmitted files is hard, because someone else controls them and you never know when they are going to change. Logging the original file as well as a receipt of the import is very import and shouldn't be overlooked either. You can make that as simple or as complex as you want, but I tend to write a receipt to a db and copy the primary key from that table into a foreign key in the table I have imported the data into, then never change that data. I like to keep a unmolested copy of the import on the file system as well as on the DB server because there are inevitable conversion / transformation issues that you will need to track down.
Hope this helps, because this is not a trivial task. I think you are on the right track, but instead of processing/importing each line separately...write them to a separate file. I am assuming this is financial data, which is one of the reasons I think provability at every step is important.
I think the FileHelpers library solves a number of your problems:
Strong types
Delimited
Fixed-width
Record-by-Record operations
I'm sure you could consolidate this into a type hierarchy that could tie in custom binary formats as well.
Have you looked at something using Linq? This is a quick example of Linq to Text and Linq to Csv.
I think it would be much simpler to use "yield return" and IEnumerable to get what you want working. This way you could probably get away with only having 1 method on your interface.

how to create multiple objects and enumerate them in c#

my problem is as follows:
Im building a console application which asks the user for the numbers of objects it should create and 4 variables that have to be assigned for every object.
The new objects name should contain a counting number starting from 1.
How would you solve this?
Im thinking about a class but im unsure about how to create the objects in runtime from userinput. Is a loop the best way to go?
What kind of class, struct, list, array .... would you recommend. The variables in the object are always the same type but i need to name them properly so I can effectivly write methods to perform operations on them in a later phase of the program.
Im just learning the language and I would be very thankful for a advice on how to approach my problem.
If I understand your problem correctly:
class MyClass
{
public int ObjectNumber { get; set; }
public string SomeVariable { get; set; }
public string AnotherVariable { get; set; }
}
// You should use keyboard input value for this
int objectsToCreate = 10;
// Create an array to hold all your objects
MyClass[] myObjects = new MyClass[objectsToCreate];
for (int i = 0; i < objectsToCreate; i++)
{
// Instantiate a new object, set it's number and
// some other properties
myObjects[i] = new MyClass()
{
ObjectNumber = i + 1,
SomeVariable = "SomeValue",
AnotherVariable = "AnotherValue"
};
}
This doesn't quite do what you described. Add in keyboard input and stuff :) Most of this code needs to be in some kind of Main method to actually run, etc.
In this case, I've chosen a class to hold your 4 variables. I have only implemented 3 though, and I've implemented them as properties, rather than fields. I'm not sure this is necessary for your assignment, but it is generally a good habit to not have publically accessible fields, and I don't want to be the one to teach you bad habits. See auto-implemented properties.
You mentioned a struct, which would be an option as well, depending on what you want to store in it. Generally though, a class would be a safer bet.
A loop would indeed be the way to go to initialize your objects. In this case, a for loop is most practical. It starts counting at 0, because we're putting the objects in an array, and array indexes in C# always start at 0. This means you have to use i + 1 to assign to the object number, or the objects would be numbered 0 - 9, just like their indexes in the array.
I'm initializing the objects using object initializer syntax, which is new in C# 3.0.
The old fashioned way would be to assign them one by one:
myObjects[i] = new MyClass();
myObjects[i].ObjectNumber = i + 1;
myObjects[i].SomeVariable = "SomeValue";
Alternatively, you could define a constructor for MyClass that takes 3 parameters.
One last thing: some people here posted answers which use a generic List (List<MyClass>) instead of an array. This will work fine, but in my example I chose to use the most basic form you could use. A List does not have a fixed size, unlike an array (notice how I initialized the array). Lists are great if you want to add more items later, or if you have no idea beforehand how many items you will need to store. However, in this case, we have the keyboard input, so we know exactly how many items we'll have. Thus: array. It will implicitly tell whoever is reading your code, that you do not intend to add more items later.
I hope this answered some questions, and raised some new ones. See just how deep the rabbit hole goes :P
Use a list or an array. List example:
int numberOfObjects = 3;
List<YourType> listOfObjects = new List<YourType>();
for(int i = 0 ; i < numberOfObjects ; i++ )
{
// Get input and create object ....
// Then add to your list
listOfObjects.Add(element);
}
Here, listOfObjects is a Generic list that can contain a variable number of objects of the type YourType. The list will automatically resize so it can hold the number of objects you add to it. Hope this helps.
If I understood what you are asking you could probably do something like this:
class Foo
{
private static int count;
public string name;
public Foo(...){
name = ++count + "";
}
}
I'm guessing what you're trying to do here, but this is a stab in the dark. The problem I'm having is dealing with the whole "the new objects name should contain a counting number starting from 1" thing. Anyway, here's my attempt:
public class UserInstantiatedClass
{
public int UserSetField1;
public int UserSetField2;
public int UserSetField3;
public int UserSetField4;
public string UserSpecifiedClassName;
}
public static class MyProgram
{
public static void Main(string [] args)
{
// gather user input, place into variables named
// numInstances, className, field1, field2, field3, field4
List<UserInstantiatedClass> instances = new List< UserInstantiatedClass>();
UserInstantiatedClass current = null;
for(int i=1; i<=numInstances; i++)
{
current = new UserInstantiatedClass();
current.UserSpecifiedClassName = className + i.ToString(); // adds the number 1, 2, 3, etc. to the class name specified
current.UserSetField1 = field1;
current.UserSetField2 = field2;
current.UserSetField3 = field3;
current.UserSetField4 = field4;
instances.Add(current);
}
// after this loop, the instances list contains the number of instances of the class UserInstantiatedClass specified by the numInstances variable.
}
}

Categories

Resources