I have following file names in my files folder
1000_A.csv
1000_B.csv
1000_C.csv
1001_A.csv
1001_B.csv
files names starting with same ID needs to be added to a list and then the list needs to added to a dictionary with ID as key
For ex:
list x contains "1000_A.csv", "1000_B.csv", "1000_C.csv"
add this to a dictionary with ID 1000 as the key Please help.
You can use LINQ's GroupBy:
Dictionary<int, List<string>> idFilenames = fileList
.Select(fileName =>
{
string fnwoe = Path.GetFileNameWithoutExtension(fileName);
string idPart = fnwoe.Split('_').First();
int id;
int.TryParse(idPart, out id);
return new { fileName, id };
})
.GroupBy(x => x.id)
.ToDictionary(g => g.Key, g => g.Select(x => x.fileName).ToList());
var folder = GetFolder();
var files = new Dictionary<int, List<string>>();
foreach (var file in folders)
{
int id = Convert.ToInt32(file.Substring(0, file.IndexOf('_'));
if (files.Any(x => x.Key == id))
files[id].Add(file);
else
{
var newList = new List<string>();
newList.Add(file);
files.Add(id, newList);
}
}
var listOfFiles = ...; // assuming you can read the list of filenames
// into a string[] or IList<string>
var d = listOfFiles.GroupBy( f => f.Substring( 0, f.IndexOf( '_' ) ) )
.ToDictionary( g => g.Key, g => g );
e.g CSV the list of your csv files
Loop through you CSV list:
Dictionary<string, int> Dict = new Dictionary<string, int>();
List<string> files = new List<string>();
foreach (string path CSV)
{
if(!ContainsKey(path.Substring(0,3))
{
files.Add(path);
Dict.Add(path.Substring(0,3),files);
}
else
{
files.Add(path);
Dict[path.Substring(0,3)].Add(file);
}
}
Related
I am currently facing an issue where I want to add different values to the same Key in a foreach loop.
List<KeyValuePair<string, Dictionary<string, string>>> sysList = new List<KeyValuePair<string, Dictionary<string, string>>>();
Dictionary<string, string> newSystem = new Dictionary<string, string>();
string line1="";
string line2="";
string quit="";
foreach(Worksheet ws in workbook.Worksheets)
{
while(quit != q)
{
newSystem.Clear();
line1 = Console.ReadLine();
line2 = Console.ReadLine();
quit = Console.ReadLine();
}
newSystem.Add(line1, line2);
sysList.Add(new KeyValuePair<string, Dictionary<string, string>>(ws.Name,newSystem));
}
For the first iteration (within while) of the first Worksheet ws everything is fine. If the I choose to do >1 iterations within this Worksheet, there is a new entry added, but the Dictionary values are all the same, f.e.:
syList[0]: "worksheetName","test1","test2"
syList[1]: "worksheetName","test1","test2"
syList[2]: "worksheetName","test1","test2"
If there are several foreach iterations, the names stay the same, but the Dictionary Key and Values added by newSys are the same [AFTER the second foreach iteration]:
syList[0]: "worksheetName1","test1","test2"
syList[1]: "worksheetName1","test1","test2"
syList[2]: "worksheetName1","test1","test2"
syList[3]: "worksheetName2","test1","test2"
syList[4]: "worksheetName2","test1","test2"
Initially I tried using Dictionaries, but could not handle the same keys properly and did not find a proper solution except for using List.
I am very grateful for any help provided.
If there are additional details that you require, please, let me know.
Edit:
desired result (example):
#########: ws.Name, line1, line2
syList[0]: "worksheetName1","ABC","1"
syList[1]: "worksheetName1","DEF","2"
syList[2]: "worksheetName1","ABC","5"
syList[3]: "worksheetName2","ABD","4"
syList[4]: "worksheetName2","ZZZ","1"
In case you don't want to maintain any uniqueness in the keys and just want a flat list, you can use the C#7 tuple syntax to build your list.
List<string> sheetNames = new List<string>() { "worksheetName1", "worksheetName2" };
var sysList = new List<(string SheetName, string line1, string line2)>();
string line1 = string.Empty;
string line2 = string.Empty;
string quit = string.Empty;
foreach (var sheet in sheetNames)
{
while (quit != "E")
{
line1 = Console.ReadLine();
line2 = Console.ReadLine();
quit = Console.ReadLine();
sysList.Add((sheet, line1, line2));
}
quit = string.Empty;
}
Try code below :
List<List<string>> syList = new List<List<string>>() {
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName1","test1","test2"},
new List<string>() {"worksheetName2","test1","test2"},
new List<string>() {"worksheetName2","test1","test2"}
};
Dictionary<string, Dictionary<string, List<string>>> dict = syList
.GroupBy(x => x.First(), y => y)
.ToDictionary(x => x.Key, y => y
.GroupBy(a => a.Skip(1).FirstOrDefault(), b => b.Last())
.ToDictionary(a => a.Key, b => b.ToList()));
//using normal looping
Dictionary<string, Dictionary<string, List<string>>> dict2 = new Dictionary<string, Dictionary<string, List<string>>>();
foreach (List<string> sy in syList)
{
if (dict2.ContainsKey(sy[0]))
{
Dictionary<string, List<string>> tempDict = dict2[sy[0]];
if (tempDict.ContainsKey(sy[1]))
{
tempDict[sy[1]].Add(sy[2]);
}
else
{
List<string> newList = new List<string>() { sy[2] };
tempDict.Add(sy[1], newList);
}
}
else
{
Dictionary<string, List<string>> newDict = new Dictionary<string, List<string>>();
newDict.Add(sy[1], new List<string> { sy[2] });
dict2.Add(sy[0], newDict);
}
}
I have a string output that looks like this:
ID = GC5c.U.feab4bc5-8-92e-c486eaddddf8
AESKEY1 = efbf5c9db259e345c205b0da27f6fb459D
AESKEY2 = ea85af9f1e5f42ff4fe8b9f07e7dcebc68
DESKEY1 = 6388a9e1a2fc8981189f0f412ae4e8
ID = JNPa.T.71664548-82-be2-a51aadd4a6f3
AESKEY1 = 37af9242c8879414e420f46903c16adebd3
AESKEY2 = 1259a1f6f6da03cb3984a117ca617d9ff73
DESKEY1 = 9547dc08db70cb95789f3a59e5c6adebd31
How can I iterate through the ID(s) of this list and obtain the values within the string?
Open the file, iterate through each line, and put it into a Dictionary<string, string>
Dictionary<string, string> data = new Dictionary<string, string>();
using(StreamReader reader = new StreamReader("C:/YourFilePath.txt"))
{
while (reader.Peek() >= 0)
{
string[] line = reader.ReadLine().Split('=');
data.Add(line[0].TrimEnd(), line[1].TrimStart());
}
}
UPDATE: Note that this solution is using Dictionary, and so it does not allow duplicate keys. If you need to duplicate keys, I would suggest changing this solution for a List<KeyValuePair<string, string>>. The code will get a little dirtier by the way:
List<KeyValuePair<string, string>> data = new List<KeyValuePair<string, string>>();
using(StreamReader reader = new StreamReader("C:/YourFilePath.txt"))
{
while (reader.Peek() >= 0)
{
string[] line = reader.ReadLine().Split('=');
data.Add(new KeyValuePair(line[0].TrimEnd(), line[1].TrimStart()));
}
}
I am not sure Regex is the best suited for this scenario, however, please find below a solution using it with a named group "id".
var regex = new Regex(#"id.*=\s*(?<id>.+)", RegexOptions.IgnoreCase);
var input = #"ID = Gs3c.H.feab4bc5-6c00-4ee8-9e2e-c486eaddddf8
AESKEY1 = efbf5c9db259e345c205b0da27f6fb459D
AESKEY2 = ea85af9f1e5f42ff4fe8b9f07e7dcebc68
DESKEY1 = 6388a9e1a2fc8981189f0f412ae4e8
ID = JNPa.T.71664548-82-be2-a51aadd4a6f3
AESKEY1 = 37af9242c8879414e420f46903c16adebd3
AESKEY2 = 1259a1f6f6da03cb3984a117ca617d9ff73
DESKEY1 = 9547dc08db70cb95789f3a59e5c6adebd31";
var ids = regex.Matches(input).Cast<Match>().Select(m => m.Groups["id"]);
Here is the Regex test: Regex test
NicoRiff's suggestion of using regular parsing into a Dictionary is the way to go. Here's the obligatory LINQ-based approach:
var data = File.ReadLines("C:/your/file/path.txt")
.Select(l => l.Split('='))
.ToDictionary(k => k[0], v => v[1]);
EDIT: As Nico pointed out, when the dictionary is going to contain duplicate keys, then a dictionary won't work. However, you can still use LINQ to automatically arrange the dictionary so that the ID field of your source text is the key instead of the field names. For example, you can use the following:
var data = File.ReadLines("C:/your/file/path.txt")
.Where(l => !String.IsNullOrEmpty(l))
.Select((l, i) => new { ID = i / 4, Value = l.Split('=') })
.GroupBy(x => x.ID)
.Select(g => new { ID = g.First().Value[1].Trim(), Values = g.ToDictionary(k => k.Value[0].Trim(), v => v.Value[1].Trim()) })
.ToDictionary(k => k.ID, v => v.Values);
Afterwards, you can iterate through data to get your fields:
foreach (var d in data.Values)
{
string id = d["ID"];
string aesKey1 = d["AESKEY1"];
string aesKey2 = d["AESKEY2"];
string desKey1 = d["DESKEY1"];
}
If you like to put the data into a dictionary like: Dicationary<string, Dictionary<string,string>>
Where the key of the main dictionary is the value of ID, and the internal dictionaries are the values that follows, then the following would do it:
string[] lines = input.Split('\n');
var myDict = new Dictionary<string, Dictionary<string,string>>();
var currentKey = "";
foreach (string[] keyVal in lines.Where(line=>!string.IsNullOrWhiteSpace(line))
.Select(line => line.Split('=')))
{
if (keyVal[0].StartsWith("ID"))
{
currentKey = keyVal[1].Trim();
myDict.Add(currentKey, new Dictionary<string, string>());
}
else
{
myDict[currentKey].Add(keyVal[0].Trim(), keyVal[1].Trim());
}
}
The Regex would look like so:
#"^ID\s+=\s+(.+)$"
You can test it on Regex101 and Rextester
Given a return of type "AccountItem", I want to filter and sort to a new list of type FDKeyValue<>
I am trying to do this without looping and I thought I could do something like this:
var monthlyList = accountList.Where(x => x.RoleType == "Metric")
.OrderBy(x => x.EntityName)
.Select(new FDKeyValue<long, string>{}
{
"Field", "Field"
}
);
here is what I have working with a loop
var accountList = DBEntity.ReturnAccountListBySearch((int)this.PageLanguageType, "");
var monthlyList = accountList.Where(x => x.RoleType == "Metric").OrderBy(x => x.EntityName).ToList();
this.MonthlyAccountList = new FDKeyValue<long,string>();
foreach (var item in monthlyList)
{
this.MonthlyAccountList.Add(item.EntityID, item.EntityName);
}
This syntax must help
var monthlyList = accountList.Where(x => x.RoleType == "Metric")
.OrderBy(x => x.EntityName)
.Select(x => new FDKeyValue<long, string>
{
x.EntityID, x.EntityName
}
);
How can I use LINQ to select all the Company Name and Company ID from all the rows? I need something like this pseudo-code:
var typedQry = from b in allData.AsEnumerable()
where b.GetHeader("xxx") == "08/10/09 to 08/26/09"
select CompanyName, CompanyID, ...
The code below selects only one Company Name. Instead, I want Company Name from all the rows:
var typedQry3 = from b in allData.AsEnumerable()
select new { compname0 = b._rows[0][5]};
The data in _rows are Company Name (e.g., allData[0]._rows[0][5], allData[0]._rows[1][5],....), Company ID, and so forth.
However, Company Name, Company ID, and etc. are not defined in the DataProperty class. Their values are inserted into _rows from data files.
Any help is appreciated. Below is some code to help you understand my question.
List<DataProperty> allData = new List<DataProperty>();
The DataProperty class consists of
private readonly Dictionary<string, string> _headers = new Dictionary<string, string>();
private readonly List<string[]> _rows = new List<string[]>();
and these methods (among others):
public string[] GetDataRow(int rowNumber){return _rows[rowNumber];}
public void AddDataRow(string[] row){_rows.Add(row);}
according to your comment, if you need to the sum for each company you can try this:
var RowList1 = allData.SelectMany(u => u._rows.Select(t => new
{
CompanyName = t[5],
Amount = Convert.ToInt64(t[1]) + Convert.ToInt64(t[2])
}))
.Where(u => u.CompanyName == "XXX")
.OrderBy(u => u.CompanyName)
.ToList();
and if you need to sum of the all companies, you can try this:
var SumAmount = allData.SelectMany(u => u._rows.Select(t => new
{
CompanyName = t[5],
Amount = Convert.ToInt64(t[1]) + Convert.ToInt64(t[2])
}))
.Where(u => u.CompanyName == "XXX")
.DefaultIfEmpty()
.Sum(u => u.Amount);
you can write your own and customized query using these
you can use this to get all company names:
var AllCompanyNames = allData.SelectMany(u => u._rows.Select(t => t[5])).ToList();
and this, to get more property:
var Rows = allData.SelectMany(u =>
u._rows.Select(t => new
{
CompanyName = t[5],
Other1 = t[1],
Other2 = t[2]
}))
.ToList();
and this, if you need to check any condition:
var FilteredRows = allData.SelectMany(u =>
u._rows.Select(t => new
{
CompanyName = t[5],
Other1 = t[1],
Other2 = t[2]
}))
.Where(u => u.CompanyName == "XXX")
.ToList();
At first you can receive rows and then iterate through them.
This example may help you
var rows = (from DataRow dRow in dTable.Rows
select new {col1=dRow["dataColumn1"],col2=dRow["dataColumn2"]});
foreach (var row in distinctRows)
{
var value1=row.col1.ToString();
var value2=row.col2.ToString();
}
To get the details of files, Directory.Getfiles("DirectoryPath", "*.zip") is returning me the all the files in a directory. Each file has a DateTime stamp in the Filename as a Postfix:
e.g.
{87fbf03b-ec94-44a0-aac5-ffbaf6416700}_20100204_145154634008919142146021.zip
I am splitting out the GUID from the above file name.
string filName = Path.GetFileNameWithoutExtension(testFile).Split('_')[0];
This explanation is just to tell you guys that thats how I can have more than one file with the same name in the same directory.
Now my question is How can i get the results same like Group by query in T-SQL? I need to know how many times a similar file name is there in that directory.
Is it possible through linq? Yes then how?
Sure, use Enumerable.GroupBy:
var groups = from f in Directory.GetFiles("DirectoryPath", "*.zip")
group f by f.Split('_')[0] into g
select new {
GUID = g.Key
Count = g.Count()
};
foreach(var group in groups) {
Console.WriteLine("Guid = {0}: Count = {1}", group.GUID, group.Count);
}
It just reads so beautifully.
Since you specified in a comment that you can not use LINQ:
Dictionary<string, int> dict = new Dictionary<string, int>();
foreach(string filename in Directory.GetFiles("DirectoryPath", "*.zip")) {
string guid = filename.Split('_')[0];
if(!dict.ContainsKey(guid)) {
dict.Add(guid, 0);
}
dict[guid]++;
}
foreach(KeyValuePair<string, int> kvp in dict) {
Console.WriteLine("Guid = {0}: Count = {1}", kvp.Key, kvp.Value);
}
Try this (not tested):
IList<string> fileNames = ...
var result = from fileName in fileNames
group fileName by fileName.Split('_')[0] into grp
select new
{
FileName = grp.Key,
Count = grp.Count()
};
Instead of string you should use Guid type.
var groups = from f in System.IO.Directory.GetFiles("DirectoryPath", "*.zip")
group f by f.Split('_')[0] into g
select new
{
GUID = new Guid(g.Key),
Count = g.Count()
};