I can't seem to find much on this online :(
For my course I have to get text from a grocery.txt file and output an invoice.
The text file looks like this:
regular,bread,2.00,2
regular,milk,2.00,3
regular,cereal,4.00,1
fresh,rump steak,11.99,0.8
fresh,apple,4.60,1.00
fresh,cucumber,2.20,0.936
regular,cream,2.20,1
regular,mustard,3.30,1
fresh,carrots,1.79,1.5
regular,tomato sauce,2.95,1
regular,salt,2.80,1
fresh,bananas,4.00,1.2
Currently I use this method to get the text:
string[] groceryItemsArray = System.IO.File.ReadAllLines(#"C:\C\groceries.txt");
What I get is an array that in stores the entire line (for example "fresh,bananas,4.00,1.2").
I have no idea how to split the array into sub arrays or even whats the best way to go about this. Unfortunately this course task are way too advanced for the little material we have been taught and time we have for this. I have already spend around 6 hours watching videos and getting not very far in learning the advanced stuff.
This is what I am trying to accomplish.
A. Class named grocerrItem. This class has properties:
name and price
this class must have 2 constructors
A. subclass of this is a purchasedItem.
this class has an integer property 'quantity'
one of its methods findCost, calculates the cost of the item, including 10% GST.
the formula for this is price * quantity * 1.1
C. A subclass of this class (purchasedItem), freshItem has
a property weight, a double type.
The findCost method here, uses the formula:wieght * price, as it is not subject to GST.
Groceries.txt contains information as follows:
type(regular or fresh), name, price, quantity/weight - depending on being regular or fresh.
** An invoice should be represented as a collection of grocery items (parent class). This can be done using any container structure i.e. array, list or collection. you will then use iteration
You can just use String.Split which returns you the sub array that you want.
public static void Main()
{
string[] groceryItemsArray = System.IO.File.ReadAllLines(#"C:\C\groceries.txt");
// now split each line content with comma. It'll return you an array (sub-array)
foreach (var line in groceryItemsArray)
{
string[] itemsInLine = line.Split(',');
// Do whatevery you want to do with this.
// e.g. for 1st line itemsInLine array will contains 4 items
// "regular","bread","2.00", "2"
}
}
You can use this code (I'm not sure what exactly you looking for):
/// It's return all text as a single list
var groceryItemsArray = System.IO.File.ReadAllLines(#"C:\C\groceries.txt")
.SelectMany(x => x.Split(new char[]{','} , StringSplitOptions.RemoveEmptyEntries)).ToList() ;
Or if want to return as Child List can use this code:
var groceryItemsArray = System.IO.File.ReadAllLines(#"C:\C\groceries.txt").Select(x =>
new { Child = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) }).ToList();
I didn't really understand what are you trying to output, but here's some basic things I did understand on your question:
(code not tested)
I created a parent class:
class GroceryItem
{
public string ItemName {get;set;}
public decimal Price {get;set;}
public GroceryItem() { }
}
And creates a child class:
class PurchasedItem : GroceryItem
{
public int Quantity { get;set; }
public decimal Cost { get;set; }
public PurchasedItem(string[] item)
{
ItemName = item[1];
Price = decimal.Parse(item[2]);
Quantity = int.Parse(item[3]);
FindCost();
}
private void FindCost()
{
Cost = Price * Quantity * 1.1;
}
}
Using your input to get all groceryItems, you can iterate using foreach loop and collect a list of purchasedItems.
Main()
{
string[] groceryItems = System.IO.File.ReadAllLines(#"C:\C\groceries.txt");
var purchasedItems = new List<PurchasedItem>();
foreach (var item in groceryItems)
{
string[] line = item.Split(',');
purchasedItems.Add(new PurchasedItem(line));
}
}
Well if you didn't understand this basic concept of programming, you better start on this link.
Related
After reading a web-page i got the following text.
Weekend of March 23 - 25, 2018
Title
Weekend
Gross
Weeks
Pacific Rim: Uprising
$28.1M
$17M
1
Spider Man: Home Coming
$37.8M
$12M
3
My problem is that i can't get all titles just like
Pacific Rim: Uprising & Spider Man: Home Coming (in this example) so do you suggest any solution for that, i really tried a lot of codes but nothing worked for me, it seems to be so hard since i can't depend on something for example it would be easier to copy what goes after "title:" and stop when there is empty line.
Update
i have figured out that all titles can be found on lines number 30,46,62... but how to write a code that copies specific lines! can you help me with that?
What you need is a parser. But, in order to parse text, there has to be some underlying structure present. Luckily, there is just enough in this case to be serviceable.
Pacific Rim: Uprising
$28.1M
$17M
1
Spider Man: Home Coming
$37.8M
$12M
3
Each movie entry consists of a single identifying pattern: 2 lines that contain "$" signs, followed by a simple integer. So a simple solution consists of 2 methods: a method to read all the contents of the file, one line at a time, and a method to parse a movie entry, once it is located:
public class Movie
{
public string Title {get;set;}
public decimal Gross {get;set;}
public decimal Weekly {get;set;}
public int Weeks {get;set;}
}
public void ReadMovies()
{
List<Movie> movies = new List<Movie>();
string[] lines = File.ReadAllLines("movies.txt");
int cursor = 0;
while (cursor < lines.Length)
{
if (lines[cursor].Contains("$"))
{
movies.Add(ParseMovie(lines, ref cursor));
}
cursor++;
}
}
public Movie ParseMovie(string[] lines, ref int cursor)
{
Movie result = new Movie();
// this method is called when we reach the gross dollar figure, so
// we have to back up to get the title
result.Title = lines[--cursor];
// these lines assume that the parse methods will succeed; if the
// underlying structure of the text is more uncertain, these should be
// replaced with the 'TryParse' pattern
result.Gross = decimal.Parse(lines[++cursor].Trim('$', 'M'));
result.Weekly = decimal.Parse(lines[++cursor].Trim('$', 'M'));
result.Weeks = int.Parse(lines[++cursor]);
// we return from this method with the cursor on the last line
// of the movie entry -- this will be incremented when we return
// in the ReadMovies method
return result;
}
The solution is based on a few assumptions :
You have a list of all the movies(not the HTML/retrieved movies but a list of all movies released)
You have list(the html file-as u mentioned) that has movie titles and details , line after line,one below the other
Firstly get the names of all the movies.Google for it and add them to a text file.Then read the text file and add the names/titles to a list.Then we create a list of the retrieved movie names.Then we compare two lists for matches and return the title(match)
Follow the below code snippet :
List<string> movieList = new List<string>;
movieList.Add(File.ReadAllLines("C:\\movies.txt"));
List<string> retrievedList = new List<string>; ///The list of retrieved movie list
retrievedList.Add(File.ReadAllLines("C:\\retrievedmovies.html"));
foreach (var item in retrievedList)
{
if (movieList.Contains(item) == true)
{
continue;
MessageBox.Show(item)
}
else
{
}
}
Hope this helps...If it doesn't , please leave a comment before down-voting
Context: I am designing a leader board and want to have the data displayed from the highest score to the lowest score. The problem being the data contains a string and integers which are imported from a text file. Currently I am able to sort the data numerically however I am using the OrderByDescending function which does not work. E.g 11,4,5,8,23,65 when ordered = 8,65,5,4,23,11 (sorted alphanumerically).
The list contains the data: name(string), difficulty(string) and score(int) and I wish to sort the data in a descending order: E.g 1st = 10, 2nd = 9 etc.
List<string> leaderboardList = new List<string>();
StreamReader srUserData = new StreamReader(#"User Leaderboard.txt");
while ((userDataLine = srUserData.ReadLine()) != null)
{
leaderboardList.Add(userDataLine);
}
leaderboardList = leaderboardList.OrderByDescending(x => Regex.Match(x, #"\d+").Value).ToList();
The Regex.Match finds the number in the string.
Basically the final line is the line that needs amending.
All help welcome, thanks.
Edit: The data should be outputted in the form Name, difficulty, score and sort the data in a descending order with the highest score.
Just change:
leaderboardList = leaderboardList.OrderByDescending(x =>
Regex.Match(x, #"\d+").Value).ToList();
To:
leaderboardList = leaderboardList.OrderByDescending(x =>
Int32.Parse(Regex.Match(x, #"\d+").Value)).ToList();
Just add the Int32.Parse really. A caveat though: If you pass a string that is not a number Int32.Parse() will throw an exception. If this is a possibility that needs to be handled, then you can use Int32.TryParse instead.
Ex:
int testValue = 0; //This is only used for TryParse()
leaderboardList = leaderboardList.OrderByDescending(x =>
Int32.TryParse(Regex.Match(x, #"\d+").Value, out testValue)
? testValue : 0M).ToList();
Tested using the following example list:
List<string> leaderboardList = new List<string>();
leaderboardList.Add("Brandon|Easy|9");
leaderboardList.Add("Yoda|Impossible|9001");
leaderboardList.Add("Barney|Easy|-1");
leaderboardList.Add("John|Normal|500");
This code works correctly, and the TryParse code was not needed.
Output:
Yoda|Impossible|9001
John|Normal|500
Brandon|Easy|9
Barney|Easy|-1
I suggest a completely different approach from the others. Load your string from disk, then parse it into a class you have defined. For example:
public class LeaderboardRow
{
public string Name { get; set; }
public string Difficulty { get; set; }
public int Score { get; set; }
}
Then your code would look more like this:
List<LeaderboardRow> leaderboardList = new List<LeaderboardRow>();
StreamReader srUserData = new StreamReader(#"User Leaderboard.txt");
while ((userDataLine = srUserData.ReadLine()) != null)
{
//Put logic here that parses your string row into 3 distinct values
leaderboardList.Add(new LeaderboardRow()
{
Score = 0, //put real value here
Name = string.Empty, //put real value here
Difficulty = string.Empty //put real value here
});
}
Then any ordering you need to do is a simple LINQ statement:
leaderboardList = leaderboardList.OrderByDescending(x => x.Score).ToList();
Depending on your scenario/requirements you could store this text as json instead which could speed up and simplify your application.
You could go old school and perform Integer.TryParse or some derivative of such functions. Once you do that you can append them into a list of integers.
int number;
bool result = Int32.TryParse(value, out number);
if (result) {
Console.WriteLine("Converted '{0}' to {1}.", value, number);
}
You can use this for ordering list of numbers in string or list of string that contains numbers.
The Alphanum Algorithm
I hope this works for you.
You missed one thing, that is you are not convert Regex value to int. Please check below code, it's works for me.
CODE:
List<string> leaderboardList = new List<string>();
leaderboardList.Add("A,A,9");
leaderboardList.Add("B,B,8");
leaderboardList.Add("G,C,65");
leaderboardList.Add("S,B,10");
leaderboardList = leaderboardList.OrderByDescending(x =>Convert.ToInt32((string.IsNullOrEmpty(Regex.Match(x, #"\d+").Value)?"0":Regex.Match(x, #"\d+").Value))).ToList();
foreach (var item in leaderboardList)
{
Console.WriteLine(item);
}
Online output: .Net Fiddle Output
I've searched a lot but can't find the answer that I understand enough to translate into my project. What is the goal: I need to find an item with the highest armor_class parameter on the list, and add that items' armor_class to character's armor class.
So, we have a list created this way:
public List<Weapon> characterInvWeapon;
public List<Armor> characterInvArmor;
etc.
Here's how class Armor and its properties are created:
public class Armor : Item, IComparable <Armor> {
public string armor_prof;
public string armor_category;
public int armor_class;
public int armor_str_req;
public string armor_stealth_mod;
public Armor (string c_name
, string c_description
, bool c_stackable
, int c_value
, string c_coin_type
, int c_weight
, string c_armor_prof
, string c_armor_category
, int c_armor_class
, int c_armor_str_req
, string c_armor_stealth_mod) : base (c_name, c_description, c_stackable, c_value, c_coin_type, c_weight)
{
armor_prof = c_armor_prof;
armor_category = c_armor_category;
armor_class = c_armor_class;
armor_str_req = c_armor_str_req;
armor_stealth_mod = c_armor_stealth_mod;
}
public int CompareTo(Armor other)
{
if (armor_class == other.armor_class)
return String.Compare (name, other.name); // a < ab < b
else
return other.armor_class - armor_class;
}
}
Armor is a class inheriting from class Item, which has the first 6 properties. Armors are stored in a list specific to Armor - public List<Armor> characterInvArmor;.
Example item:
AddToItemStore(new Armor("Breastplate", "Description.", false, 400, "gp", 20, "Breastplate", "Medium Armor", 14, 0, ""));
Adding script:
public void AddToCharacterInventory(Item it)
{
if (it is Weapon)
{
charInvWeapon.Add((Weapon)it);
charInvWeapon.Sort();
}
else if (it is Armor)
{
charInvArmor.Add((Armor)it);
charInvArmor.Sort();
}
}
Now as I mentioned, I need to find an item on the list charInvArmor with highest armor_class parameter and use its value in other function, which calculates armor class from many variables.
So in other function, characterArmorClass = armorWithHighestArmorClass + otherVariable + someotherVariable; etc.
I suspect there are some handy shortcuts in Linq, but I'd be most thankful for some example without Linq. Linq would be welcome too, but I'm absolutely new to it and also I'm worried about performance and my apps compatibility with iPhone, for example. I've read iOS can cause problems with Linq. This must be fast and compatible calculation.
With LINQ:
int maxArmorClass = characterInvArmor.Max(armor => armor.armor_class);
Without LINQ with Sort:
var list = characterInvArmor.ToList(); // copy list, so we do not break sorted orded
list.Sort((armor1, armor2) => armor2.armor_class.CompareTo(armor1.armor_class));
int maxArmorClass = list[0].armor_class;
And of course you can always write a manual method with a cycle and "max" variable.
BTW, I noticed, that you sort charInvArmor in AddToCharacterInventory method. If array is always sorted, then, based on your CompareTo implementation, an item with maximum armor_class should always be last (or first, I'm not sure). So just take the last (first) element of your list.
You have to loop through the list and check each value since the list is not sorted based on the armor class value and you do not want to use LINQ:
int maxArmorClass = 0;
foreach (var armor in characterInvArmor)
{
// Do a comparison here and see if you found a higher value
// If a higher value is found, store it in maxArmorClass
}
As a side note I recommend the following links:
Public Fields versus Automatic Properties
and
Style guide for c# * In C#, Pascal casing and camel casing are the established conventions.
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.
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.
}
}