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;
Related
I have (for certain reasons not to get into now...) a List of the following structure:
List1<Dictionary1<string, List2<Dictionary2<string, string>>>>
(I added the 1 and 2 naming for clarity).
I want to iterate over List1 and sum up Dictionary1, so that all values of identical keys in Dictionary2 will add up.
For example if each Dictionary1 item contains a Dictionary2:
{ "Price", 23},
{ "Customers", 3}
then I want to iterate over all List2 elements, and over all List1 elements, and have a final dictionary of the total sum of all prices and customers as a single key for each category:
{ "Price", 15235},
{ "Customers", 236}
I hope that's clear.. In other words, I want to sum up this double-nested list in a way that I'm left with all unique keys across all nested dictionaries and have the values summed up.
I believe it can be done with LINQ, but I'm not sure how to do that..
This may be the ugliest thing I've ever written, and makes some assumptions on what you're doing, but I think this gets you what you want:
var query = from outerDictionary in x
from listOfDictionaries in outerDictionary.Values
from innerDictionary in listOfDictionaries
from keyValuePairs in innerDictionary
group keyValuePairs by keyValuePairs.Key into finalGroup
select new
{
Key = finalGroup.Key,
Sum = finalGroup.Sum(a => Convert.ToInt32(a.Value))
};
Where x is your main List.
Ok, so it looks like that you were attempting to create an Dictionary of Items with various properties (Cost, Customers, etc...), which begs the question: why not just create a class?
After all, it would be pretty simple to turn your dictionary of dictionary of items into a single dictionary of properties, such as below.
public class ItemProperties
{
public double Price {get; set;} = 0;
public int Customers {get; set;} = 0;
//Whichever other properties you were thinking of using.
}
static ItemProperties AddAll(Dictionary<string, ItemProperties> items)
ItemProperties finalitem = new ItemProperties();
{
foreach (var item in items)
{
finalitem.Price += item.Price;
finalitem.Customers += item.Customers;
//Repeat for all other existing properties.
}
return finalitem;
}
Of course, this only works if the number and kind of properties is immutable. Another way to approach this problem would be to use TryParse to find properties in Dictionary2 that you think can be added. This is problematic however, and requires some good error checking.
static Dictionary < string, string > AddNestedDictionary(Dictionary < string, Dictionary < string, string > items) {
Dictionary < string, string > finalitem = new Dictionary < string, string > ();
foreach(var item in items) {
foreach(var prop in item) {
if (!finalitem.ContainsKey(prop.Key)) {
finalitem.Add(prop);
}
double i = 0;
if (Double.TryParse(prop.Value, out i)) {
finalitem[prop.Key] += i;
}
}
}
return finalitem;
}
Again, not the best answer compared to the simplicity of a static class. But that would be the price you pay for nonclarity.
I want to sort a List Array on the basis of an array item.
I have a List Array of Strings as below:
List<String>[] MyProjects = new List<String>[20];
Through a loop, I have added five strings
(Id, Name, StartDate, EndDate, Status)
to each of the 20 projects from another detailed List source.
for(int i = 0; i<20; i++){
MyProjects[i].Add(DetailedProjectList.Id.ToString());
MyProjects[i].Add(DetailedProjectList.Name);
MyProjects[i].Add(DetailedProjectList.StartDate);
MyProjects[i].Add(DetailedProjectList.EndDate);
MyProjects[i].Add(DetailedProjectList.Status)}
The Status values are
"Slow", "Normal", "Fast", "Suspended" and "" for unknown status.
Based on Status, I want to sort MyProject List Array.
What I have done is that I have created another List as below
List<string> sortProjectsBy = new List<string>(){"Slow", "Normal", "Fast", "", "Suspended"};
I tried as below to sort, however unsuccessful.
MyProjects = MyProjects.OrderBy(x => sortProjectsBy.IndexOf(4));
Can anyone hint in the right direction. Thanks.
I suggest you to create class Project and then add all the fields inside it you need. It's much nicer and scalable in the future. Then create a List or an Array of projects and use the OrderBy() function to sort based on the field you want.
List<Project> projects = new List<>();
// Fill the list...
projects.OrderBy(project => project.Status);
The field Status has to be a primitive type or needs to implement the interface IComparable in order for the sorting to work. I suggest you add an enum for Status with int values.
First consider maybe to use Enum for status and put it in a different file lite (utils or something) - better to work like that.
enum Status {"Slow"=1, "Normal", "Fast", "", "Suspend"}
Now about the filtering you want to achieve do it like this (you need to tell which attribute of x you are referring to. In this case is status)
MyProjects = MyProjects.OrderBy(x => x.status == enum.Suspend);
Read about enums :
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum
Read about lambda expressions :
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
First of all, storing project details as List is not adivisable. You need to create a Custom Class to represent them.
For example,
public class DetailedProjectList
{
public string Name {get;set;}
public eStatus Status {get;set;}
// rest of properties
}
Then You can use
var result = MyProjects.OrderBy(x=> sortProjectsBy.IndexOf(x.Status));
For example
List<string> sortProjectsBy = new List<string>(){"Slow", "Normal", "Fast", "", "Suspended"};
var MyProjects= new List<DetailedProjectList>{
new DetailedProjectList{Name="abc1", Status="Fast"},
new DetailedProjectList{Name="abc2", Status="Normal"},
new DetailedProjectList{Name="abc3", Status="Slow"},
};
var result = MyProjects.OrderBy(x=> sortProjectsBy.IndexOf(x.Status));
Output
abc3 Slow
abc2 Normal
abc1 Fast
A better approach thought would be to use Enum to represent Status.
public enum eStatus
{
Slow,
Normal,
Fast,
Unknown,
Suspended
}
Then your code can be simplified as
var MyProjects= new List<DetailedProjectList>{
new DetailedProjectList{Name="abc1", Status=eStatus.Fast},
new DetailedProjectList{Name="abc2", Status=eStatus.Normal},
new DetailedProjectList{Name="abc3", Status=eStatus.Slow},
};
var result = MyProjects.OrderBy(x=> x.Status);
Ok so you have a collection of 20 items. Based on them you need to create a list of strings(20 DetailedProjectList items).
What you can do to solve your problem is to SORT YOUR COLLECTION before you create your list of strings. In this way your list of strings will be sorted.
But your code is not optimal at all. So you should concider optimization on many levels.
Lets say you have ProjectDetail class as follow:
private class ProjectDetail
{
public int Id {get;set;}
public string Name {get;set;}
DateTime StartDate {get;set;} = DateTime.Now;
DateTime EndDate {get;set;} = DateTime.Now;
public string Status {get;set;}
public string toString => $"{Id} - {Name} - {StartDate} - {EndDate} - {Status}";
}
Notice that I have added a toString attribute to make things easier, and I also have added default values.
Then your program could be like:
static void Main(string[] args)
{
var projectDetails = MockProjectItems();
Console.WriteLine("Before sortig:");
foreach (var item in projectDetails)
{
Console.WriteLine(item.toString);
}
var myProjects = projectDetails.OrderBy(p => p.Status).Select(p => p.toString);
Console.WriteLine("\n\nAfter sorting:");
foreach (var item in myProjects)
{
Console.WriteLine(item);
}
}
where the helper method is
private static List<ProjectDetail> MockProjectItems()
{
var items = new List<ProjectDetail>(20);
for(int i = 0; i < 20 ; i += 4){
items.Add(new ProjectDetail{Id = i, Name = "RandomName "+i, Status = "Slow"});
items.Add(new ProjectDetail{Id = i+1, Name = "RandomName "+(i+1), Status = "Normal"});
items.Add(new ProjectDetail{Id = i+2, Name = "RandomName "+(i+2), Status = "Fast"});
items.Add(new ProjectDetail{Id = i+3, Name = "RandomName "+(i+3), Status = "Suspended"});
}
return items;
}
Then your program should print the following:
I need to save those six fields in same column but not in same row and same cell. each field have default GUID.so i decided to put that default guid's in one list and fields in one list and call that object of that particular list where we want .
ArrayList Alist = new ArrayList();
{
Alist.Add("FD713788-B5AE-49FF-8B2C-F311B9CB0CC4");
Alist.Add("64B512E7-46AE-4989-A049-A446118099C4");
Alist.Add("376D45C8-659D-4ACE-B249-CFBF4F231915");
Alist.Add("59A2449A-C5C6-45B5-AA00-F535D83AD48B");
Alist.Add("03ADA903-D09A-4F53-8B67-7347A08EDAB1");
Alist.Add("2F405521-06A0-427C-B9A3-56B8931CFC57");
}
ArrayList objValue = new ArrayList();
{
objValue.Add(viewmodel.TinNo);
objValue.Add(viewmodel.CstNo);
objValue.Add(viewmodel.PanNo);
objValue.Add(viewmodel.CinNo);
objValue.Add(viewmodel.ExciseRegNo);
objValue.Add(viewmodel.ServiceTaxNo);
}
var TaxInfoTaxFiledclassobj = new TaxInfoTaxFiled()
{
TaxInfoTaxFieldID = TaxInfoTaxFieldObj,
TaxFieldID = new Guid(Alist .ToString ()),
FieldValue = objValue.ToString(),
};
All are working Fine
but in TaxFieldID it show the count which has been calculated from list but while saving it show the below error
What shall I do?
You're trying to pass an ArrayList as a Guid. In this line:
TaxFieldID = Guid.Parse(Alist.ToString())
You need to select just one of the elements of the ArrayList to parse. Additionally, you could use a List<Guid> to eliminate the problem altogether.
List<Guid> guidList = new List<Guid>();
guidList.Add(new Guid("DDE4BA55-808E-479F-BE8B-72F69913442F"));
...
TaxFieldID = guidList[0]; // obviously, select the appropriate GUID
Guid.Parse() is capable of parsing a GUID. Alist.ToString() should not be a GUID.
EDIT
I guess you're looking for something like this -
var listFiled = new List<TaxInfoTaxFiled>();
for(var item = 0; item < objValue.Count ; item++)
{
listFiled.Add(new TaxInfoTaxFiled
{
TaxInfoTaxFieldID = TaxInfoTaxFieldObj,
TaxFieldID = new Guid(Alist[item]),
FieldValue = objValue[item]
});
}
AList is an array, not a Guid.
You must be doing Guid.Parse on entries of AList
Something like
foreach(string g in AList)
{
Guid guid = Guid.Parse(g);
// Guid guid = new Guid(g) also works
}
I'm new to C# and programming as a whole and I've been unable to come up with a solution to what I want to do. I want to be able to create a way to display several arrays containing elements from three external text files with values on each line (e.g. #"Files\Column1.txt", #"Files\Column2.txt" #"Files\Column3.txt"). They then need to be displayed like this in the command line:
https://www.dropbox.com/s/0telh1ils201wpy/Untitled.png?dl=0
I also need to be able to sort each column individually (e.g. column 3 from lowest to highest).
I've probably explained this horribly but I'm not sure how else to put it! Any possible solutions will be greatly appreciated!
One way to do it would be to store the corresponding items from each file in a Tuple, and then store those in a List. This way the items will all stay together, but you can sort your list on any of the Tuple fields. If you were doing anything more detailed with these items, I would suggest creating a simple class to store them, so the code would be more maintainable.
Something like:
public class Item
{
public DayOfWeek Day { get; set; }
public DateTime Date { get; set; }
public string Value { get; set; }
}
The example below could easily be converted to use such a class, but for now it uses a Tuple<string, string, string>. As an intermediate step, you could easily convert the items as you create the Tuple to get more strongly-typed versions, for example, you could have Tuple<DayOfWeek, DateTime, string>.
Here's the sample code for reading your file items into a list, and how to sort on each item type:
public static void Main()
{
// For testing sake, I created some dummy files
var file1 = #"D:\Public\Temp\File1.txt";
var file2 = #"D:\Public\Temp\File2.txt";
var file3 = #"D:\Public\Temp\File3.txt";
// Validation that files exist and have same number
// of items is intentionally left out for the example
// Read the contents of each file into a separate variable
var days = File.ReadAllLines(file1);
var dates = File.ReadAllLines(file2);
var values = File.ReadAllLines(file3);
var itemCount = days.Length;
// The list of items read from each file
var fileItems = new List<Tuple<string, string, string>>();
// Add a new item for each line in each file
for (int i = 0; i < itemCount; i++)
{
fileItems.Add(new Tuple<string, string, string>(
days[i], dates[i], values[i]));
}
// Display the items in console window
fileItems.ForEach(item =>
Console.WriteLine("{0} {1} = {2}",
item.Item1, item.Item2, item.Item3));
// Example for how to order the items:
// By days
fileItems = fileItems.OrderBy(item => item.Item1).ToList();
// By dates
fileItems = fileItems.OrderBy(item => item.Item2).ToList();
// By values
fileItems = fileItems.OrderBy(item => item.Item3).ToList();
// Order by descending
fileItems = fileItems.OrderByDescending(item => item.Item1).ToList();
// Show the values based on the last ordering
fileItems.ForEach(item =>
Console.WriteLine("{0} {1} = {2}",
item.Item1, item.Item2, item.Item3));
}
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.