In Step 1 I wrote this code to access pre-existing list & add value in it .
In Step 2 I updated the dictionary with new list.
In Step 3 again I have to access the list inside dictionary to print the result.
Is there any process or shortcut to add new values to this pre-existing list directly inside dictionary without updating it?
Only have to write the code inside Main. Rest was hardcoded in the compiler & can't be changed.
Your Help will be appreciated. Suggestions are welcome :)
using System;
using System.Collections.Generic;
namespace AddNewMember
{
public class Club
{
static Dictionary<int, string> groupInfo = new Dictionary<int, string>() { { 1, "Gold" }, { 2, "Silver" }, { 3, "Platinum" } };
static Dictionary<int, List<String>> memberInfo = new Dictionary<int, List<String>>() {
{ 1, new List<string>(){ "Tom","Harry"} },
{ 2,new List<string>(){ "Sam","Peter"} },
{ 3,new List<string>(){ "Kim","Robert"} } };
public static void Main(string[] args)
{
//Write your code here. Above part is hardcoded can't be changed
Console.WriteLine("Group Name :");
string gName = Console.ReadLine();
int num = 0;
foreach (KeyValuePair<int, string> VARIABLE in groupInfo)
{
if (VARIABLE.Value == gName)
{
num = VARIABLE.Key;
}
}
Console.WriteLine("Member Name:");
string name = Console.ReadLine();
//Step 1
List<string> l = memberInfo[num];
l.Add(name);
//Step 2
memberInfo[num] = l;
//Step 3
List<string> r = memberInfo[num];
foreach (var VARIABLE in r)
{
Console.WriteLine(VARIABLE);
}
}
}
}
Seems to me like your understanding of dictionaries is upside down. You use the key to retrieve the value, not the other way round. If you're looking to have the user enter a group name (gold, silver, bronze) and then the name of the person to add to that group, you should make the dictionary map a string (group name) to a list of members
static Dictionary<string, List<String>> groupInfo = new() {
{ "Gold", new(){ "Tom","Harry" } },
{ "Silver", new(){ "Sam","Peter"} },
{ "Platinum", new(){ "Kim","Robert"} }
};
public static void Main(string[] args)
{
Console.WriteLine("Group Name :");
string gName = Console.ReadLine();
Console.WriteLine("Member Name :");
string mName = Console.ReadLine();
groupInfo[gName].Add(mName);
}
Yep, that's it. GroupInfo maps string group names to list of string member names, calling groupInfo[gName] resolves to a List of string, so the Add method call there is being performed on the list and the given member name is added
Side note, I'm leveraging a facility of recent c# where you don't have to repeat the type name on both sides of the =. The compiler will know that groupInfo is a Dictionary<string, List<string>> and when it seems new() in the initializer it knows I mean new List<string> which can really help tidy things up. The parentheses are necessary otherwise it would think I was trying to make an anonymous type, which is a different thing. If you get compiler errors you might have to restore the type names if your c# is older
We don't need to re-assign modified list into dictionary value. Step #2 is redundant. When you retrieve the list from step #1. It return a pointer (reference) to the list in the dictionary. It means, when you perform insert an item into the list variable, the list in dictionary is updated (new item added).
Also, In step #3, you get the r but not used.
Related
Each instance of some Lists in my program are in an arbitrarily different order (as a result of an unfixed bug in Umbraco CMS Forms), and I need to rearrange them to the correct order. I can't use indices and OrderBy as each time the order is different.
I have been trying to iterate the existing List, then, when it finds the correct String that should be in position [0], using .Add to add it to another, empty List. Then continue through adding each value to the correct index.
I can't figure out a way to do this. I need the logic to basically say "look in this list, if the string equals this value, add it to this other list at position 0, then look for the next string to add at position 1, and so on", so at the end I will have the new List in the correct order.
// List to populate from record in wrong order
var extractedFields = new List<KeyValuePair<string, string>>();
// new list to copy values across in correct order
var newOrderFields = new List<KeyValuePair<string, string>>();
// separate list containing data field captions, used to iterate later
var extractedCaptions = new List<string>();
foreach (var field in record.RecordFields)
{
var extractValue = field.Value.ValuesAsString().NullSafeToString();
var extractType = CGHelper.CleanString(field.Value.Field.FieldType.Name).ToLower();
var extractCaption = field.Value.Field.Caption;
extractedFields.Add(new KeyValuePair<string, string>(extractType,
extractValue));
extractedCaptions.Add(extractCaption);
}
var count = 0;
foreach (var cap in extractedCaptions.ToList())
{
if (cap == "Opportunity ID")
{
extractedCaptions.Remove(cap);
extractedCaptions.Insert(0, cap);
var key = extractedFields[count].Key;
var value = extractedFields[count].Value;
newOrderFields.Add(new KeyValuePair<string, string>(key, value));
}
else if (cap == "Name")
{
// etc. identify string to be put into correct order
So to try and explain further, a user submits a form with the fields in a certain order. When we load that form and pull the record through (from the Umbraco Form), it is in a totally different and arbitrary order (and is in a different order for every single form).Therefore I need to iterate the fields and put them back into the order they were in the original form...
I don't know if I understand the situation correctly. But you can utilize the IComparer<T> interface for custom sorting logic.
using System;
using System.Collections.Generic;
namespace Comparer
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
var list = new[]{"Foobar", "Baz", "Foo", "Foobar", "Bar", };
Array.Sort(list, new CustomComparer(new[]{"Foo", "Bar", "Baz", "Foobar"}));
list.Dump();
// will dump : Foo,Bar,Baz,Foobar,Foobar
}
}
public class CustomComparer : IComparer<string>
{
private readonly string[] priorityList;
public CustomComparer(string[] priorityList)
{
this.priorityList = priorityList;
}
public int Compare(string x, string y)
{
var xIx = Array.IndexOf(priorityList, x);
var yIx = Array.IndexOf(priorityList, y);
return xIx.CompareTo(yIx);
}
}
}
This will sort the array according to indexes proved in the constructor.
Fiddle
I wrote a small example.
You can see it working here.
The idea is iterating the ordered list and search to every value in other one.
Code:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
List<string> ordered = new List<string>(){ "a", "b", "c", "d"};
List<string> nonOrderedAndMissing = new List<string>(){ "c", "d", "a"};
// here is the join
var newList = ordered.Select(a => nonOrderedAndMissing.Contains(a) ? a : null).Where(d => d != null).ToList();
// checking here
foreach(var a in newList){
Console.WriteLine(a);
}
}
}
I have a list of items which have names and I need to iterate them, but I also need to know how many times this item with the same name it is. So this is an example:
-----
|1|A|
|2|B|
|3|C|
|4|C|
|5|C|
|6|A|
|7|B|
|8|C|
|9|C|
-----
So, when I'm iterating and I'm on row 1, I want to know it is the first time it is an A, when I'm on row 6, I want to know it is the second time, when I'm on row 9, I want to know it is the 5th C, etc. How can I achieve this? Is there some index I can keep track of? I was also thinking of filling a hash while iterating, but perhaps thats too much.
You can use Dictionary<char, int> for keeping count of each character in your list
here your key will be character and value will contain number of occurrences of that character in list
Dictionary<char, int> occurances = new Dictionary<char, int>();
List<char> elements = new List<char>{'A', 'B','C','C','C','A','B', 'C', 'C'};
int result = 0;
foreach(char element in elements)
{
if(occurances.TryGetValue(element, out result))
occurances[element] = result + 1;
else
occurances.Add(element, 1);
}
foreach(KeyValuePair<char, int> kv in occurances)
Console.WriteLine("Key: "+ kv.Key + " Value: "+kv.Value);
Output:
Key: A Value: 2
Key: B Value: 2
Key: C Value: 5
POC: dotNetFiddler
Use dictionary to keep track of counter.
List<string> input = new List<string> { "A", "B", "C", "C", "C", "A", "B", "C", "C" };
Dictionary<string, int> output = new Dictionary<string, int>();
foreach(var item in input)
{
if (output.ContainsKey(item))
{
output[item] = output[item] + 1;
}
else
{
output.Add(item, 1);
}
}
I think you'll need a reversed index instead of row store index.
Row store index just like your table described, and reversed index store terms to search indexes.
Probably like this:
A 1,6
B 2,7
C 3,4,5,8,9
The search engine such like 'Elastic search/Solr' will store terms like this.
If you are in C#, Dictionary<string, List<int>> is pretty much good for you. There you can keep your data that is reverse indexed.
The clean way is to implement your own list; the item is your own object. By this method, you implement your own Iterator pattern with an additional property in your object and your own Add() method. The new Iterator should inherit List and should override the Add() method of List.
I implement this for my own. you can use it. keep in mind, this solution is one of some solutions that exist. However, I think this is one the best solutions with respect to SOLID and OO principals.
public class CounterIterator : List<Item>
{
public new void Add(Item item)
{
base.Add(item);
foreach (var listItem in this)
{
if (listItem.Equals(item))
{
item.CountRepeat++;
}
}
}
}
public class Item
{
public Item(string value)
{
Value = value;
}
public string Value { get; private set; }
public int CountRepeat { get; set; }
public override bool Equals(object obj)
{
var item = obj as Item;
return item != null && Value.Equals(item.Value);
}
}
I tested the code above. It is an extension of List which has an added behavior. If anyone thinks it is not a correct answer, please mention me in comments. I will try to clarify the issue.
I'm trying to find the most time efficient way of classifying expenses on a piece of Accounting Software. The values come in like this:
"EFTPOS Kathmandu 2342342"
I have created a method as follows:
private static string Classifier(string inputDescription)
{
Dictionary<string, string> classified = new Dictionary<string, string>();
classified.Add("D/C FROM", "INCOME" );
classified.Add("CREDIT ATM", "INCOME");
classified.Add("INTEREST", "INCOME");
classified.Add("EFTPOS", "EXPENSE" );
classified.Add("DEBIT DEBIT", "EXPENSE");
classified.Add("CC DEBIT", "EXPENSE");
classified.Add("PAYMENT RECEIVED", "TRANSFER");
classified.Add("PAYMENT - THANK YOU", "TRANSFER");
classified.Add("IRD", "TAX" );
classified.Add("I.R.D", "TAX");
try
{
// What do I do here to get the value?
return value;
}
catch(Exception)
{
return "OTHER";
}
}
Basically, I want to run through the values of my inputDescription against the keys in the dictionary to get its value (the classification of the line item).
So for the example shown above, the result would be "EXPENSE".
I assumed dictionary would be the fastest way to approach this, but open to suggestions on better methods.
Thanks in Advance!
What about using RegEx?
const string EXPENSE_PATTERN = "^(EFTPOS|DEBIT DEBIT|CC DEBIT)"
const string ..._PATTERN
if (Regex.IsMatch(input, EXPENSE_PATTERN)){
return "EXPENSE";
} else if (Regex.IsMatch(input, INCOME_PATTERN)){
return "INCOME";
} else if (Regex.IsMatch(input, ..._PATTERN)){
return "...";
} else {
return "OTHER"
}
One of the way to achieve this is
string input = "EFTPOS Kathmandu 2342342";
string value = string.Empty;
foreach (var key in input.Split(' '))
{
value = classified.Where(k => classified.ContainsKey(k.Key)).Select(k => classified[k.Key]).FirstOrDefault();
if(value != null & value.trim()!= string.empty)
break;
}
Check the value is null or not for further use. foreach loop will break once will find value.
Calling method:
static void Main(string[] args)
{
Console.WriteLine(Classifier("EFTPOS Kathmandu 2342342"));
Console.WriteLine(Classifier("D/C FROM Kathmandu 2342342"));
Console.ReadKey();
}
Classifier method:
private static string Classifier(string inputDescription)
{
var classified = new Dictionary<string, string>
{
{ "D/C FROM", "INCOME" },
{ "CREDIT ATM", "INCOME" },
{ "INTEREST", "INCOME" },
{ "EFTPOS", "EXPENSE" },
{ "DEBIT DEBIT", "EXPENSE" },
{ "CC DEBIT", "EXPENSE" },
{ "PAYMENT RECEIVED", "TRANSFER" },
{ "PAYMENT - THANK YOU", "TRANSFER" },
{ "IRD", "TAX" },
{ "I.R.D", "TAX" }
};
try
{
foreach (var kvp in classified)
if (inputDescription.StartsWith(kvp.Key))
return kvp.Value;
return "OTHER";
}
catch
{
return "OTHER";
}
}
Returns:
EXPENSE
INCOME
Of course you could move the Dictionary definition outside of the method and make it a class member. That would especially make sense if you have multiple frequent calls to Classifier. You could also define it as an IReadOnlyDictionary to prevent changes to its contents.
The easiest way to get something from a dictionary is by using the key like:
Dictionary<string, string> classified = new Dictionary<string, string>();
var value = classified[key];
but of-course you would wanna check for the key occurence in dictionary like:
if(classified.ContainsKey(key))
return classified[key];
else
throw new InvalidTypeException();//this is because you should have all the key's mapped i.e you are only expecting known key types.People prefer other types like they would return null but i throw coz my dictionary is not having this key
Now coming to the values:
All the Values seem to be known and repeated types.So i would build an enum:
enum TransactionType
{
Expense,
Income,
Transfer
}
enum Source
{
EFTPOS,
DEBIT DEBIT,
...so on...
}
i prefer enums to avoid magic strings and people do make mistakes while typing strings.
So with the Combination of Dictionary and enum now i would build as :
private Dictionary<Source,TransactionType> PopulateSource()
{
Dictionary<Source,TransactionType> classified = new Dictionary<Source,TransactionType>();
//populate dictionary by iterating using
var keys = Enum.GetValues(typeof(Source));
var values = Enum.GetValues(typeof(TransactionType));
you can just iterate through keys if your keys and values in enum are in order .
return classified ;
}
public void TestSourceTransaction()
{
TransactionType transType;
var classifieds = PopulateSource();
var key = GetSourceType(inputDescription);//you need to write a method to get key from desc based on regex or string split options.
if(classifieds.ContainsKey(key))
classifieds[key].Value;
else
throw new InvalidTypeException("Source type undefined");
}
I prefer clean and expandable code and absolute no to magic string.
I have something like this:
Dictionary<int, List<string>> fileList = new Dictionary<int, List<string>>();
and then, I fill it with some variables, for example:
fileList.Add(
counter,
new List<string> {
OFD.SafeFileName,
OFD.FileName,
VERSION, NAME , DATE ,
BOX , SERIAL_NUM, SERIES,
POINT , NOTE , VARIANT
}
);
Where counter is a variable that increment +1 each time something happens, List<string>{XXX} where XXX are string variables that holds some text.
My question is, how do I access these strings from the list, if counter == 1?
You can access the data in the dictionary and lists just like normal. Remember, access a value in the dictionary first, which will return a list. Then, access the items in the list.
For example, you can index into the dictionary, which returns a list, and then index into the list:
------ Returns a list from the dictionary
| --- Returns an item from the list
| |
v v
fileList[0][0] // First item in the first list
fileList[1][0] // First item in the second list
fileList[1][1] // Second item in the second list
// etc.
FishBasketGordo explains how you can access entries in your data structure. I will only add some thoughts here:
Dictionaries (based on hash tables) allow fast access to arbitrary keys. But your keys are given by a counter variable (counter = 0, 1, 2, 3, 4 ...). The fastest way to access such keys is to simply use the index of an array or of a list. Therefore I would just use a List<> instead of a Dictionary<,>.
Furthermore, your list seems not to list anonymous values but rather values having very specific and distinct meanings. I.e. a date is not the same as a name. In this case I would create a class that stores these values and that allows an individual access to individual values.
public class FileInformation
{
public string SafeFileName { get; set; }
public string FileName { get; set; }
public decimal Version { get; set; }
public string Name { get; set; }
public DateTime Date { get; set; }
...
}
Now you can create a list like this:
var fileList = new List<FileInformation>();
fileList.Add(
new FileInformation {
SafeFileName = "MyDocument.txt",
FileName = "MyDocument.txt",
Version = 1.2,
...
}
}
And you can access the information like this
decimal version = fileList[5].Version;
If the keys don't start at zero, just subtract the starting value:
int firstKey = 100;
int requestedKey = 117;
decimal version = fileList[requestedKey - firstKey].Version;
Dictionary uses Indexer to access its vallues via key.
List<string> items = fileList[counter];
var str0 = items[0];
var str1 = items[1];
Then you can do anything with the list.
Dictionary<int, List<string>> fileList = new Dictionary<int, List<string>>();
fileList.Add(101, new List<string> { "fijo", "Frigy" });
fileList.Add(102, new List<string> { "lijo", "liji" });
fileList.Add(103, new List<string> { "vimal", "vilma" });
for (int Key = 101; Key < 104; Key++)
{
for (int ListIndex = 0; ListIndex < fileList[Key].Count; ListIndex++)
{
Console.WriteLine(fileList[Key][ListIndex] as string);
}
}
You can access the List through MyDic[Key][0]. While editing the list, there won't be any run time errors, however it will result in unnecessary values stored in Dictionary. So better:
assign the MyDict[Key] to new list
edit the new list and then
reassign the new list to MyDict[Key] rather than editing a
particular variable in the Dictionary with List as Values.
Code example:
List<string> lstr = new List<string(MyDict[Key]);
lstr[0] = "new Values";
lstr[1] = "new Value 2";
MyDict[Key] = lstr;
I have dictionary that is populated and I have no control of.
I need to modify the value how can I do that?
I have put a noddy example together to explain the problem
class Program
{
static void Main(string[] args)
{
Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>();
CustomerOrderDictionary.Add(new Customer { Id = 1, FullName = "Jo Bloogs" },3);
CustomerOrderDictionary.Add(new Customer { Id = 2, FullName = "Rob Smith" },5);
//now I decide to increase the quantity but cannot do the below as value has no setter
foreach (var pair in CustomerOrderDictionary)
{
if(pair.Key.Id==1)
{
pair.Value = 4;///ERROR HERE
}
}
}
}
public class Customer
{
public int Id { get; set; }
public string FullName { get; set; }
}
Any suggestions?
Thanks a lot
I suggest you work out which keys need modifying first, and then iterate over those modifications. Otherwise you'll end up modifying a collection while you're iterating over it, which will throw an exception. So for example:
// The ToList() call here is important, so that we evaluate all of the query
// *before* we start modifying the dictionary
var keysToModify = CustomerOrderDictionary.Keys
.Where(k => k.Id == 1)
.ToList();
foreach (var key in keysToModify)
{
CustomerOrderDictionary[key] = 4;
}
The problem here is that pair is typed to KeyValuePair which is a readonly object and can't be modified. Additionally the KeyValuePair collection is a way of viewing the contents of the dictionary (not changing it).
What you want to do here is just modify the dictionary directly. The Key in the KeyValuePair can be used to update the same entry in the dictionary.
if(pair.Key.Id==1) {
CustomerOrderDictionary[pair.Key] = 4;
}
EDIT
As Jon pointed out the assignment will invalidate the iterator. The simplest, but ineffecient route, is to copy the enumerator at the start of the loop.
foreach (var pair in CustomerOrderDictionary.ToList())
Here is an alternate approach
1) Create a new class
// wrapper class to allow me to edit a dictionary
public class IntWrapper
{
public int OrderCount{ get; set; }
}
2) Change this declaration
Dictionary<Customer, IntWrapper> CustomerOrderDictionary = new Dictionary<Customer, IntWrapper>();
3) Assign your variable
pair.Value.OrderCount = 4;
foreach (Customer customer in customers.Keys)
{
if ( customer.Id == 1 )
customers[ customer ] = 4;
}
CustomerOrderDictionary[1] = 4;
Here's one way to do that (just the assigning a value part..):
CustomerOrderDictionary[new Customer { Id = 1, FullName = "Jo Bloogs" }]=4
Notice that "1" is not a key in your dictionary. a Customer is, so you'll have to use that.
Notice also that Customer Should implement IEquatable as explained here
Ok, in your example you're effectively just finding the entry for the Customer object with Id = 1 and updating the associated value. In practice, I think that your code will likely be able to obtain a reference to your intended Customer object prior to updating the associated value in the dictionary. If that is the case, then there's no need for a loop.
Below is a very simple example where a loop is not needed because your code already has a reference to the customer1 variable. While my example is overly simplified, the concept is that you could potentially obtain a reference to your desired Customer object through some means other than iterating over the dictionary.
static void Main(string[] args)
{
Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>();
Customer customer1 = new Customer { Id = 1, FullName = "Jo Bloogs" };
Customer customer2 = new Customer { Id = 2, FullName = "Rob Smith" };
CustomerOrderDictionary.Add(customer1, 3);
CustomerOrderDictionary.Add(customer2, 5);
// you already have a reference to customer1, so just use the accessor on the dictionary to update the value
CustomerOrderDictionary[customer1]++;
}
If you need to perform some kind of update on multiple Customer objects based on some other criteria, then you might need a loop. The following example assumes that you'll have some collection other than the dictionary that stores your Customer objects, and that you can use that collection of Customer objects to identify the ones whose associated value in the dictionary need to be updated.
static void Main(string[] args)
{
// presumably you will have a separate collection of all your Customer objects somewhere
List<Customer> customers = new List<Customer>();
Customer customer1 = new Customer { Id = 1, FullName = "Jo Bloogs" };
Customer customer2 = new Customer { Id = 2, FullName = "Rob Smith" };
Customer customer3 = new Customer { Id = 3, FullName = "Rob Zombie" };
customers.Add(customer1);
customers.Add(customer2);
customers.Add(customer3);
Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>();
CustomerOrderDictionary.Add(customer1, 3);
CustomerOrderDictionary.Add(customer2, 5);
// let's just say that we're going to update the value for any customers whose name starts with "Rob"
// use the separate list of Customer objects for the iteration,
// because you would not be allowed to modify the dictionary if you iterate over the dictionary directly
foreach (var customer in customers.Where(c => c.FullName.StartsWith("Rob")))
{
// the dictionary may or may not contain an entry for every Customer in the list, so use TryGetValue
int value;
if (CustomerOrderDictionary.TryGetValue(customer, out value))
// if an entry is found for this customer, then increment the value of that entry by 1
CustomerOrderDictionary[customer] = value + 1;
else
// if there is no entry in the dictionary for this Customer, let's add one just for the heck of it
CustomerOrderDictionary.Add(customer, 1);
}
}
If this is not the case and the only source of Customer objects that you have available is the dictionary itself, then you'll need to perform some kind of cloning/copying of those objects out to a separate list/array prior to iterating over the dictionary for modification. See Jon Skeet's answer for this case; he suggests using a Where filter on the dictionary's Keys property and uses the ToList method to create a separate List<Customer> instance for the purpose of iteration.