How to deal with a position in list that doesn't exist? - c#

I'm building this program in C# in which you can enter membership details, confirm them, and view previously stored memberships. I am still very much a beginner and this is just some school homework.
My teacher suggested to write and read membership details to a file but I had no idea how to do this efficiently so just added them all to a list. I wrote this part to retrieve the username, password and membership type.
However, how do I stop an 'unhandled' error if the user enters a value in which doesn't have any stored data?
Here is the code: the list is called membersList.
Console.WriteLine("Which stored membership would you like to view? (e.g 1, 2..)");
int membChoice = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Membership Entry " + membChoice);
Console.WriteLine("Username: " + membersList[membChoice*3-3]);
Console.WriteLine("Password: " + membersList[membChoice*3-2]);
Console.WriteLine("Membership Type: " + membersList[membChoice*3-1].ToUpper());
This results in an unhandled exception error if you enter a larger value than members already stored.

You will first need to check if the list has an element at the position you want:
if(list.ElementAtOrDefault(membChoice*3-3) != null)
{
Console.WriteLine("Username: " + membersList[membChoice*3-3]);
}
That or you can do a try catch to catch the error and display something like invalid choice.

I don't think your list is efficient. I understand you save three information for the same object in three different indices.
I think a better way for comprehension when we begin to code, is to create a class for handle all of this information, like a Member class:
class Member
{
public int ID { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public string Type { get; set; }
}
And use this class for ONLY ONE index of your list:
Member member = new Member()
{
ID = 0,
Name = "Monty Python",
Password = "My favorite color is blue",
Type = "Knight"
};
List<Member> membersList = new List<Member>();
membersList.Add(member);
After you can retrieve data by searching with ID:
User userFind = membersList.Find(x => x.ID == membChoice);
And then display data:
Console.WriteLine("UserName : " + userFind.Name);

Related

Nested Lists in Unity 3d- How do I do this?

Bryce: Here are my current functions. With the list in the class, I'm not quite sure how to modify my code.
public void GetMembers()
{
DatabaseManager.Instance.SQLiteInit();
MemberList.Clear();
MemberList= DatabaseManager.Instance.MakeMembersList();
Debug.Log("How many in the list " + MemberList.Count);
ShowAllMembers();
}
public void GetEquipment()
{
DatabaseManager.Instance.SQLiteInit();
EquipmentList.Clear();
EquipmentList= DatabaseManager.Instance.MakeEquipmentList();
Debug.Log("How many in the list " + EquipmentList.Count);
ShowAllEquipment();
}
Also thought you should see the database function being called.
public List<NewEquipmentClass> MakeEquipmentList()
{
EquipmentList.Clear();
mConnection.Open();
mSQLString = "SELECT * FROM " + SQL_TABLE_EQUIPMENT + " ORDER BY " + COL_EQUIPMENT_ID;
mCommand.CommandText = mSQLString;
mCommand.ExecuteNonQuery();
mReader = mCommand.ExecuteReader();
while (mReader.Read())
{
EquipmentList.Add(new Equipment(mReader.GetString(0),
mReader.GetString(1)));
Debug.Log(mReader.GetString(0) + mReader.GetString(1));
}
mReader.Close();
mConnection.Close();
return EquipmentList;
}
Thanks!
This is the result I am looking for:
Member Name
Member's Equipment
Member's Equipment
Member's Equipment
Member Name
Member's Equipment...
Etc.
I have two lists, one for members and one for equipment. What is the best way to get the type of results above?
Thanks!
It looks like you want to create a class called Member that looks something like this
class Member {
string name;
List<Equipment> equipment;
}
where Equipment could be an object with a name and stats or whatever you need. And then have a list of them like
List<Member> members;
Obviously you'd want getters/setters/constructor etc. but if implementing this isn't clear to you I'd recommend some fundamentals of c# or Object Oriented learning.

Trying to get NetSuite Country list with enumeration value linked to code and name

I am implementing a integration with NetSuite in C#. In the external system I need to populate a list of countries that will match NetSuite's country list.
The NetSuite Web Service provides an enumeration call Country
public enum Country {
_afghanistan,
_alandIslands,
_albania,
_algeria,
...
You can also get a list of country Name and Code (in an albeit not so straight forward way) from the web service. (See: http://suiteweekly.com/2015/07/netsuite-get-all-country-list/)
Which gives you access to values like this:
Afghanistan, AF
Aland Islands, AX
Albania, AL
Algeria, DZ
American Samoa, AS
...
But, as you can see, there is no way to link the two together. (I tried to match by index but that didn't work and sounds scary anyway)
NetSuite's "help" files have a list. But this is static and I really want a dynamic solution that updates as NetSuites updates because we know countries will change--even is not that often.
Screenshot of Country Enumerations from NetSuite help docs
The only solutions I have found online are people who have provided static data that maps the two sets of data. (ex. suiteweekly.com /2015/07/netsuite-complete-country-list-in-netsuite/)
I cannot (don't want to) believe that this is the only solution.
Anyone else have experience with this that has a better solution?
NetSuite, if you are reading, come on guys, give a programmer a break.
The best solution I have come up with is to leverage the apparent relationship between the country name and the enumeration key to forge a link between the two. I am sure others could improve on this solution but what I would really like to see is a solution that isn't a hack like this that relies on an apparent pattern but rather on that is based on an explicit connection. Or better yet NetSuite should just provide the data in one place all together.
For example you can see the apparent relationship here:
_alandIslands -> Aland Islands
With a little code I can try to forge a match.
I first get the Enumeration Keys into an array. And I create a list of objects of type NetSuiteCountry that will hold my results.
var countryEnumKeys = Enum.GetNames(typeof(Country));
var countries = new List<NetSuiteCountry>();
I then loop through the list of country Name and Code I got using the referenced code above (not shown here).
For each country name I then strip all non-word characters from the country name with Regex.Replace, prepend an underscore (_) and then convert the string to lowercase. Finally I try to find a match between the Enumeration Key (converted to lowercase as well) and the matcher string that was created. If a match is found I save all the data together the countries list.
UPDATE: Based on the comments I have added additional code/hacks to try to deal with the anomalies without hard-coding exceptions. Hopefully these updates will catch any future updates to the country list as well, but no promises. As of this writing it was able to handle all the known anomalies. In my case I needed to ignore Deprecated countries so those aren't included.
foreach (RecordRef baseRef in baseRefList)
{
var name = baseRef.name;
//Skip Deprecated countries
if (name.EndsWith("(Deprecated)")) continue;
//Use the name to try to find and enumkey match and only add a country if found.
var enumMatcher = $"_{Regex.Replace(name, #"\W", "").ToLower()}";
//Compares Ignoring Case and Diacritic characters
var enumMatch = CountryEnumKeys.FirstOrDefault(e => string.Compare(e, enumMatcher, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) == 0);
//Then try by Enum starts with Name but only one.
if (enumMatch == null)
{
var matches = CountryEnumKeys.Where(e => e.ToLower().StartsWith(enumMatcher));
if (matches.Count() == 1)
{
Debug.Write($"- Country Match Hack 1 : ");
enumMatch = matches.First();
}
}
//Then try by Name starts with Enum but only one.
if (enumMatch == null)
{
var matches = CountryEnumKeys.Where(e => enumMatcher.StartsWith(e.ToLower()));
if (matches.Count() == 1)
{
Debug.Write($"- Country Match Hack 2 : ");
enumMatch = matches.First();
}
}
//Finally try by first half Enum and Name match but again only one.
if (enumMatch == null)
{
var matches = CountryEnumKeys.Where(e => e.ToLower().StartsWith(enumMatcher.Substring(0, (enumMatcher.Length/2))));
if (matches.Count() == 1)
{
Debug.Write($"- Country Match Hack 3 : ");
enumMatch = matches.First();
}
}
if (enumMatch != null)
{
var enumIndex = Array.IndexOf(CountryEnumKeys, enumMatch);
if (enumIndex >= 0)
{
var country = (Country) enumIndex;
var nsCountry = new NetSuiteCountry
{
Name = baseRef.name,
Code = baseRef.internalId,
EnumKey = country.ToString(),
Country = country
};
Debug.WriteLine($"[{nsCountry.Name}] as [{nsCountry.EnumKey}]");
countries.Add(nsCountry);
}
}
else
{
Debug.WriteLine($"Could not find Country match for: [{name}] as [{enumMatcher}]");
}
}
Here is my NetSuiteCountry class:
public class NetSuiteCountry
{
public string Name { get; set; }
public string Code { get; set; }
public string EnumKey { get; set; }
public Country Country { get; set; }
}
Let me start off with a disclaimer that I'm not a coder, and this is the first day I've tried to look at a C# program.
I need something similar for a Javascript project where I need the complete list of Netsuite company names, codes and their numeric values and when reading the help it seemed like the only way was through webservices.
I downloaded the sample application for webservices from Netsuite and a version of Visual Studio and I was able to edit the sample program provided to create a list of all of the country names and country codes (ex. Canada, CA).
I started out doing something similar to the previous poster to get the list of country names:
string[] countryList = Enum.GetNames(typeof(Country));
foreach (string s in countryList)
{
_out.writeLn(s);
}
But I later got rid of this and started a new technique. I created a class similar to the previous answer:
public class NS_Country
{
public string countryCode { get; set; }
public string countryName { get; set; }
public string countryEnum { get; set; }
public string countryNumericID { get; set; }
}
Here is the new code for getting the list of company names, codes and IDs. I realize that it's not very efficient as I mentioned before I'm not really a coder and this is my first attempt with C#, lots of Google and cutting/pasting ;D.
_out.writeLn(" Attempting to get Country list.");
// Create a list for the NS_Country objects
List<NS_Country> CountryList = new List<NS_Country>();
// Create a new GetSelectValueFieldDescription object to use in a getSelectValue search
GetSelectValueFieldDescription countryDesc = new GetSelectValueFieldDescription();
countryDesc.recordType = RecordType.customer;
countryDesc.recordTypeSpecified = true;
countryDesc.sublist = "addressbooklist";
countryDesc.field = "country";
// Create a GetSelectValueResult object to hold the results of the search
GetSelectValueResult myResult = _service.getSelectValue(countryDesc, 0);
BaseRef[] baseRef = myResult.baseRefList;
foreach (BaseRef nsCountryRef in baseRef)
{
// Didn't know how to do this more efficiently
// Get the type for the BaseRef object, get the property for "internalId",
// then finally get it's value as string and assign it to myCountryCode
string myCountryCode = nsCountryRef.GetType().GetProperty("internalId").GetValue(nsCountryRef).ToString();
// Create a new NS_Country object
NS_Country countryToAdd = new NS_Country
{
countryCode = myCountryCode,
countryName = nsCountryRef.name,
// Call to a function to get the enum value based on the name
countryEnum = getCountryEnum(nsCountryRef.name)
};
try
{
// If the country enum was verified in the Countries enum
if (!String.IsNullOrEmpty(countryToAdd.countryEnum))
{
int countryEnumIndex = (int)Enum.Parse(typeof(Country), countryToAdd.countryEnum);
Debug.WriteLine("Enum: " + countryToAdd.countryEnum + ", Enum Index: " + countryEnumIndex);
_out.writeLn("ID: " + countryToAdd.countryCode + ", Name: " + countryToAdd.countryName + ", Enum: " + countryToAdd.countryEnum);
}
}
// There was a problem locating the country enum that was not handled
catch (Exception ex)
{
Debug.WriteLine("Enum: " + countryToAdd.countryEnum + ", Enum Index Not Found");
_out.writeLn("ID: " + countryToAdd.countryCode + ", Name: " + countryToAdd.countryName + ", Enum: Not Found");
}
// Add the countryToAdd object to the CountryList
CountryList.Add(countryToAdd);
}
// Create a JSON - I need this for my javascript
var javaScriptSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string jsonString = javaScriptSerializer.Serialize(CountryList);
Debug.WriteLine(jsonString);
In order to get the enum values, I created a function called getCountryEnum:
static string getCountryEnum(string countryName)
{
// Create a dictionary for looking up the exceptions that can't be converted
// Don't know what Netsuite was thinking with these ones ;D
Dictionary<string, string> dictExceptions = new Dictionary<string, string>()
{
{"Congo, Democratic Republic of", "_congoDemocraticPeoplesRepublic"},
{"Myanmar (Burma)", "_myanmar"},
{"Wallis and Futuna", "_wallisAndFutunaIslands"}
};
// Replace with "'s" in the Country names with "s"
string countryName2 = Regex.Replace(countryName, #"\'s", "s");
// Call a function that replaces accented characters with non-accented equivalent
countryName2 = RemoveDiacritics(countryName2);
countryName2 = Regex.Replace(countryName2, #"\W", " ");
string[] separators = {" ","'"}; // "'" required to deal with country names like "Cote d'Ivoire"
string[] words = countryName2.Split(separators, StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < words.Length; i++)
{
string word = words[i];
if (i == 0)
{
words[i] = char.ToLower(word[0]) + word.Substring(1);
}
else
{
words[i] = char.ToUpper(word[0]) + word.Substring(1);
}
}
string countryEnum2 = "_" + String.Join("", words);
// return an empty string if the country name contains Deprecated
bool b = countryName.Contains("Deprecated");
if (b)
{
return String.Empty;
}
else
{
// test to see if the country name was one of the exceptions
string test;
bool isExceptionCountry = dictExceptions.TryGetValue(countryName, out test);
if (isExceptionCountry == true)
{
return dictExceptions[countryName];
}
else
{
return countryEnum2;
}
}
}
In the above I used a function, RemoveDiacritics I found here. I will repost the referenced function below:
static string RemoveDiacritics(string text)
{
string formD = text.Normalize(NormalizationForm.FormD);
StringBuilder sb = new StringBuilder();
foreach (char ch in formD)
{
UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(ch);
if (uc != UnicodeCategory.NonSpacingMark)
{
sb.Append(ch);
}
}
return sb.ToString().Normalize(NormalizationForm.FormC);
}
Here are the tricky cases to test any solution you develop with:
// Test tricky names
Debug.WriteLine(getCountryEnum("Curaçao"));
Debug.WriteLine(getCountryEnum("Saint Barthélemy"));
Debug.WriteLine(getCountryEnum("Croatia/Hrvatska"));
Debug.WriteLine(getCountryEnum("Korea, Democratic People's Republic"));
Debug.WriteLine(getCountryEnum("US Minor Outlying Islands"));
Debug.WriteLine(getCountryEnum("Cote d'Ivoire"));
Debug.WriteLine(getCountryEnum("Heard and McDonald Islands"));
// Enums that fail
Debug.WriteLine(getCountryEnum("Congo, Democratic Republic of")); // _congoDemocraticPeoplesRepublic added to exceptions
Debug.WriteLine(getCountryEnum("Myanmar (Burma)")); // _myanmar added to exceptions
Debug.WriteLine(getCountryEnum("Netherlands Antilles (Deprecated)")); // Skip Deprecated
Debug.WriteLine(getCountryEnum("Serbia and Montenegro (Deprecated)")); // Skip Deprecated
Debug.WriteLine(getCountryEnum("Wallis and Futuna")); // _wallisAndFutunaIslands added to exceptions
For my purposes I wanted a JSON object that had all the values for Coutries (Name, Code, Enum, Value). I'll include it here in case anyone is searching for it. The numeric values are useful when you have a 3rd party HTML form that has to forward the information to a Netsuite online form.
Here is a link to the JSON object on Pastebin.
My appologies for the lack of programming knowledge (only really do a bit of javascript), hopefully this additional information will be useful for someone.

How can I take objects from the second set of objects which don't exist in the first set of objects in fast way?

I have records in two databases. That is the entity in the first database:
public class PersonInDatabaseOne
{
public string Name { get; set; }
public string Surname { get; set; }
}
That is the entity in the second database:
public class PersonInDatabaseTwo
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
How can I get records from the second database which don't exist in the first database (the first name and the last name must be different than in the first database). Now I have something like that but that is VERY SLOW, too slow:
List<PersonInDatabaseOne> peopleInDatabaseOne = new List<PersonInDatabaseOne>();
// Hear I generate objects but in real I take it from database:
for (int i = 0; i < 100000; i++)
{
peopleInDatabaseOne.Add(new PersonInDatabaseOne { Name = "aaa" + i, Surname = "aaa" + i });
}
List<PersonInDatabaseTwo> peopleInDatabaseTwo = new List<PersonInDatabaseTwo>();
// Hear I generate objects but in real I take it from database:
for (int i = 0; i < 10000; i++)
{
peopleInDatabaseTwo.Add(new PersonInDatabaseTwo { FirstName = "aaa" + i, LastName = "aaa" + i });
}
for (int i = 0; i < 10000; i++)
{
peopleInDatabaseTwo.Add(new PersonInDatabaseTwo { FirstName = "bbb" + i, LastName = "bbb" + i });
}
List<PersonInDatabaseTwo> peopleInDatabaseTwoWhichNotExistInDatabaseOne = new List<PersonInDatabaseTwo>();
// BELOW CODE IS VERY SLOW:
foreach (PersonInDatabaseTwo personInDatabaseTwo in peopleInDatabaseTwo)
{
if (!peopleInDatabaseOne.Any(x => x.Name == personInDatabaseTwo.FirstName && x.Surname == personInDatabaseTwo.LastName))
{
peopleInDatabaseTwoWhichNotExistInDatabaseOne.Add(personInDatabaseTwo);
}
};
The fastest way is dependent on the number of entities, and what indexes you already have.
If there's a few entities, what you already have performs better because multiple scans of a small set takes less than creating HashSet objects.
If all of your entities fit in the memory, the best way is to build HashSet out of them, and use Except which is detailed nicely by #alex.feigin.
If you can't afford loading all entities in the memory, you need to divide them into bulks based on the comparison key and load them into memory and apply the HashSet method repeatedly. Note that bulks can't be based on the number of records, but on the comparison key. For example, load all entities with names starting with 'A', then 'B', and so on.
If you already have an index on the database on the comparison key (like, in your case, FirstName and LastName) in one of the databases, you can retrieve a sorted list from the database. This will help you do binary search (http://en.wikipedia.org/wiki/Binary_search_algorithm) on the sorted list for comparison. See https://msdn.microsoft.com/en-us/library/w4e7fxsh(v=vs.110).aspx
If you already have an index on the database on the comparison key on both databases, you can get to do this in O(n), and in a scalable way (any number of records). You need to loop through both lists and find the differences only once. See https://stackoverflow.com/a/161535/187996 for more details.
Edit: with respect to the comments - using a real model and a dictionary instead of a simple set:
Try hashing your list into a Dictionary to hold your people objects, as the key - try a Tuple instead of a name1==name2 && lname1==lname2.
This will potentially then look like this:
// Some people1 and people2 lists of models already exist:
var sw = Stopwatch.StartNew();
var removeThese = people1.Select(x=>Tuple.Create(x.FirstName,x.LastName));
var dic2 = people2.ToDictionary(x=>Tuple.Create(x.Name,x.Surname),x=>x);
var result = dic2.Keys.Except(removeThese).Select(x=>dic2[x]).ToList();
Console.WriteLine(sw.Elapsed);
I hope this helps.

during update query it throws NotSupportedException?

I am dealing with SQLite in windows store application.I am updating the values in table using
var tagPage = db.QueryAsync<MyModel>("UPDATE MyModel SET Tag =2 WHERE id = 1");
db.UpdateAsync(tagPage);
It throws an NotSupportedException on SQLite.cs class over the method
public int Update(object obj, Type objType)
{
if (obj == null || objType == null)
{
return 0;
}
var map = GetMapping(objType);
var pk = map.PK;
if (pk == null)
{
throw new NotSupportedException("Cannot update " + map.TableName + ": it has no PK");
}
var cols = from p in map.Columns
where p != pk
select p;
var vals = from c in cols
select c.GetValue(obj);
var ps = new List<object>(vals);
ps.Add(pk.GetValue(obj));
var q = string.Format("update \"{0}\" set {1} where {2} = ? ", map.TableName, string.Join(",", (from c in cols
select "\"" + c.Name + "\" = ? ").ToArray()), pk.Name);
return Execute(q, ps.ToArray());
}
because I think it wont get the primery key, where I have provided primery key in table.
I tried it with async and await but no use, why it is happening? please help me
Regarding your NotSupportedException issue - I suspect that your model is missing the PrimaryKey attribute:
public class MyModel
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public int Tag { get; set; }
public string Foo { get; set; }
}
You will need the attribute(s) above, even if your db schema already has them defined. At this time, Sqlite-Net does not read schema data from the db.
Some other thoughts:
Firstly, you should use only either the synchronous Sqlite-Net API, or the async API. Don't use both.
I personally prefer the synchronous API, as it appears to be more up to date. The async API has not been updated in 11 months, whereas the synchronous API was updated 4 months ago. Besides this I never was able to figure out how to do transactions using the async API. Again, this is personal preference.
Secondly, the Query and QueryAsync methods should be used only for querying (for SELECTs). They should not be used for UPDATEs. For adding/changing data, you will want to use these synchronous methods: Execute, Update, Insert, etc. If using the async API, there are the async counterparts (ExecuteAsync, etc).
Please read the Sqlite-Net Project page, as you will find a lot of helpful information there regarding general API usage.

RavenDB query Store

Just got to grips with RavenDB - which is awesome - however I am getting a little stuck with a query. I running a foreach and using the Store() method to save some data and once complete using the SaveChanges() method.
Once I have stored this information, I need to reference this information to store some additional information (don't worry if you slightly confused at this point the code will make it clear!) but when I reference the information there is no information to be found.
So, first of all I add some data:
foreach (var development in developments)
{
Console.WriteLine(" - Working on Developmnent ID: " + development.devID);
Session.Store(new Domain.Development
{
Id = "D" + Convert.ToString(development.devID),
Name = development.devName,
Street = development.devStreet,
Town = development.devTown,
County = development.devCounty,
Postcode = development.devPostcode,
Country = development.devCounty,
Description = "",
Longitude = GeoData.Longitude(development.devPostcode),
Latitude = GeoData.Latitude(development.devPostcode)
});
}
Now, because of the limitations with the number of queries that can be ran within the session, I retrieve the whole dataset and store in memory:
var developmentList = from d in Session.Query<Domain.Development>()
select d;
Now when I add a break point at the end of this there is no data to be found. Do I need to create another session to retrieve this data?
I have also tried
var developmentList = Session.Query<Domain.Development>();
Here is the code where I create the session too:
internal static DocumentStore Store;
internal static IDocumentSession Session { get; set; }
internal <<Constructor>> ...
Store = new DocumentStore { ConnectionStringName = "RavenDB" };
Store.Initialize();
IndexCreation.CreateIndexes(Assembly.GetCallingAssembly(), Store);
Session = Store.OpenSession();
It's not recommended you do this. Goes back to safe by default concept of RavenDB.
If you just stored those values, why do you need to save them to the database and the re-load them from the database? Just use the in memory collection and that would be it.

Categories