Save two string array values into single table using foreach - c#

In my view i am having two types of values and i am passing into string arrays. I can't concatenate both. I am using multiselect checkbox..
My code:
string[] func= { };
string[] role= { };
if (!string.IsNullOrEmpty(collection["Area"]))
func = collection["Area"].Split(',');
if (!string.IsNullOrEmpty(collection["Role"]))
roles= collection["Role"].Split(',');
foreach (string pf in func )
{
if (!string.IsNullOrEmpty(collection["role_" + func]))
role= collection["role_" + func].Split(',');
if (role!= null && role.Length > 0)
{
foreach (string rl in role)
{
prefunccpf = new prefunc();
cpf.CID= cid;
cpf.FID= Convert.ToInt32(func);
cpf.RID= Convert.ToInt32(rl);
}
}
}
In this first foreach statement i am checking functions array then it will come inside. Then Second foreach statement i am checking roles array. If roles array having count means it will save with roleId. But This conditions are goodly work if i select single function. If I select 2 and more function the loop again goes to top and again come to pref.roles. It didn't check the already those roles are saved. it is increasing again. Actually what will do for this?

I found the solution. By using Zip function in C# i got the exact result.
MY CODE HERE
string[] func= { };
string[] rol= { };
if (!string.IsNullOrEmpty(collection["Area"]))
func= collection["Area"].Split(',');
if (!string.IsNullOrEmpty(collection["Role"]))
roles= collection["Role"].Split(',');
var lstCombined = roles.Zip(func, (role, func) => new { Role = role, Function = func }).ToList();
foreach (var pf in lstCombined)
{
var cpf= new prefunc
{
CID= candidateId,
FID= Convert.ToInt32(pf .Function),
RID= Convert.ToInt32(pf .Role)
};
}

Related

LINQ or Lambda for two for loops

The code I have written works fine, this inquiry being purely for educational purposes. I want to know how others would do this better and cleaner. I especially hate the way I use two for loops to get data. There has to be a more efficient way.
I tried to do with LINQ but one of them is a class and the other one is just a string[]. So I couldn't figure out how to use it.
I have got a Document Name Table in my SQL database and Files in Content Folder.
I have got a Two list- ListOfFileNamesSavedInTheDB and ListOfFileNamesInTheFolder.
Basically, I am getting all file names saved in Database and checking is it exist in the Folder, if not delete file name from the database.
var clientDocList = documentRepository.Documents.Where(c => c.ClientID == clientID).ToList();
if (Directory.Exists(directoryPath))
{
string[] fileList = Directory.GetFiles(directoryPath).Select(Path.GetFileName).ToArray();
foreach (var clientDoc in clientDocList)
{
bool fileNotExist = true;
foreach (var file in fileList)
{
if (clientDoc.DocFileName.Trim().ToUpper()==file.ToUpper().Trim())
{
fileNotExist = false;
break;
}
}
if (fileNotExist)
{
documentRepository.Delete(clientDoc);
}
}
}
I am not exactly sure of how you want your code to work but I believe you need something like this
//string TextResult = "";
ClientDocList documentRepository = GetClientDocList();
var directoryPath = "";
var clientID = 1;
var clientDocList = documentRepository.Documents.Where(c => c.ClientID == clientID).ToList();
if (Directory.Exists(directoryPath) || true) // I need to pass your condition
{
string[] files = new string[] { "file1", "file5", "file6" };
List<string> fileList = files.Select(x => x.Trim().ToUpper()).ToList(); // I like working with lists, if you want an array it's ok
foreach (var clientDoc in clientDocList.Where(c => !fileList.Contains(c.DocFileName.Trim().ToUpper())))
{
//TextResult += $" {clientDoc.DocFileName} does not exists so you have to delete it from db";
documentRepository.Delete(clientDoc);
}
}
//Console.WriteLine(TextResult);
To be honest, I really don't like this line
fileList = files.Select(x => x.Trim().ToUpper()).ToList()
so I would suggest you add a helper function comparing the list of file names to the specific file name
public static bool TrimContains(List<string> names, string name)
{
return names.Any(x => x.Trim().Equals(name.Trim(), StringComparison.InvariantCultureIgnoreCase));
}
and your final code would become
List<string> fileList = new List<string>() { "file1", "file5", "file6" };
foreach (var clientDoc in clientDocList.Where(c => !TrimContains(fileList, c.DocFileName)))
{
//TextResult += $" {clientDoc.DocFileName} does not exists so you have to delete it from db";
documentRepository.Delete(clientDoc);
}
Instead of retrieving all documents from database and do the checking in memory, I suggest to check which document doesn't exist in folder in one query:
if (Directory.Exists(directoryPath))
{
var fileList = Directory.GetFiles(directoryPath).Select(Path.GetFileName);
var clientDocList = documentRepository.Documents.Where(c => c.ClientID == clientID && !fileList.Contains(c.DocFileName.Trim())).ToList();
documentRepository.Documents.RemoveRange(clientDocList);
}
Note: this is just a sample to demonstrate the idea, may have syntax error somewhere since I don't have IDE with me at the moment. But the idea is there
This code is not only shorter but also more efficient since it only uses a single query to retrieve documents from database. I assume the number of files in a folder is not too large to convert to SQL by EF

How to prevent a duplicate item from being generated in a Foreach loop in C#

I have a foreach loop which builds search results and sometimes it would return the same Page Name and Description, but the link would be different as it has a 3rd party Gallery Module which has different queries in the URL.
For example:
Resources/Videos/emodule/936/eitem/75 would have one video
and
/Resources/Videos/emodule/936/eitem/73 would be different.
The Title and Description is the same.
How would I change my foreach loop to check if the Page Title is the same and if it is the same, exclude the sb.AppendLine search result?
This is my current code:
TotalPageResults = "0";
var searchResults = SearchController.Instance.ModuleSearch(query);
if(searchResults != null)
{
TotalPageResults = searchResults.TotalHits.ToString();
var sb = new StringBuilder();
sb.AppendLine("<div class='page_results'><span class='page_results_text'>Page Results:</span></br>");
foreach(var result in searchResults.Results)
{
sb.AppendLine($"</br><span><a href='{result.Url}' class='page_results_link'>{result.Title}</a></span></br><span class='page_result_description'>{result.Description}</span></br><span class='page_results_date_modified'>Updated: {result.DisplayModifiedTime}</span></br>");
}
sb.AppendLine("</div>");
DNNSearchResuls = sb.ToString();
}
Keep a set of results you've already seen, and check if it's new before 'doing the thing'
var stuffImThinkinAbout = new List<string>();
var stuffIAlreadyHave = new HashSet<string>();
foreach (var i in stuffImThinkinAbout)
{
if (!stuffIAlreadyHave.Contains(i))
{
//do the thing
stuffIAlreadyHave.Add(i);
}
else
{
//skip dupe
}
}
Then use title or whatever as your 'key' to make them unique.
Would could check if the Stringbuilder already contains the title and description. Somthing along the lines:
foreach(var result in searchResults.Results)
{
if(!sb.ToString().Contains(result.Title) && !sb.ToString().Contains(result.Description)
sb.AppendLine($"</br><span><a href='{result.Url}' class='page_results_link'>{result.Title}</a></span></br><span class='page_result_description'>{result.Description}</span></br><span class='page_results_date_modified'>Updated: {result.DisplayModifiedTime}</span></br>");
}
}
Try using GroupBy on the property you want to distinct and select only one record in the group.
This code for only property Title
foreach (var result in searchResults.Results.GroupBy(p => p.Title).Select(g => g.First())
{
}
or 2 properties Title and Description
foreach (var result in searchResults.Results.GroupBy(p => new {p.Title, p.Description}).Select(g => g.First())
{
}

Get files with same/ similar name from array

I have multiple objects in an array of which the format:
id_name_date_filetype.
I need to take all the objects with, let's say same id or same name and insert them in a new array.
With the GetFiles method I already have all the object in one array and I have their names but I don't know how to differentiate them.
I have a foreach I which I'll be going through all the objects but I'm kind of stuck.
Any hints as to what do I do?
//Process the files
string[] filelist = Directory.GetFiles(SourceDirectory, "*.tsv*", SearchOption.TopDirectoryOnly).Select(filename => Path.GetFullPath(filename)).Distinct().ToArray();
foreach (string file in filelist)
{
string[] fileNameSplit = file.Split('_');
switch (fileNameSplit.Last().ToLower())
{
case "assets.tsv":
assets = ReadDataFromCsv<Asset>(file);
break;
case "financialaccounts.tsv":
financialAccounts = ReadDataFromCsv<FinancialAccount>(file);
break;
case "households.tsv":
households = ReadDataFromCsv<Household>(file);
break;
case "registrations.tsv":
registrations = ReadDataFromCsv<Registration>(file);
break;
case "representatives.tsv":
representatives = ReadDataFromCsv<Representative>(file);
break;
}
}
// Find all files from one firm and insert them in a list
foreach (string file in filelist)
{
}
Here is a linq approach as I proposed it in my comment:
First get all distinct ID's from your filelist
string [] allDistinctIDs = filelist.Select(x=>x.Split('_').First()).Distinct(). ToArray();
now you can iterate through the list of ID's and compare each value
for (int i = 0; i < allDistinctIDs.Length; i++)
{
string [] allSameIDStrings = filelist.Where(x=>x.Split('_').First() == allDistinctIDs[i]).ToArray();
}
Basically you split every item by '_' and compare the first (id part) of the string with each item from your list of distinct ID's.
Another approach would be to use GroupBy.
// example input
string[] filelist = {
"123_Name1_xxx_Asset.tsv",
"456_Name2_xxx_Asset.tsv",
"123_Name3_xxx_HouseHold.tsv",
"456_Name4_xxx_HouseHold.tsv"};
IEnumerable<IGrouping<string, string>> ID_Groups = filelist.GroupBy(x=>x.Split('_').First());
This would give you a collection of all filenames grouped by the ID:
at each position in ID_Groups is a list of items with the same ID. You can filter them by fileName:
foreach (var id_group in ID_Groups)
{
assets = ReadDataFromCsv<Asset>(id_group.FirstOrDefault(x=>x.ToLower().Contains("assets.tsv")));
// and so on
households = ReadDataFromCsv<Household>(id_group.FirstOrDefault(x=>x.ToLower().Contains("households.tsv")));
}
You gotta define what is "Similar" to you. It could be the initial letter of the file name? Half of it? Whole filename?
This function should do more or less what you want without using Linq or something more complex than loops.
var IDOffileNameIWant = object.GetFiles()[0].id;
List<string> arrayThatContainsSimilar = new List<string>();
foreach(var file in object.GetFiles())
{
if(file.Name.Split('_')[0].Contains(IDOffileNameIWant))
{
arrayThatContainsSimilar.Add(file.Name);
}
}
It's very basic and can be refined, but you gotta give more details on what is the exact result you want to obtain.
Since you're still struggling, here's a working example:
List<string> files = new List<string>() {
"123_novica_file1", "123_novica_file3", "123_novica_file2", "456_myfilename_file1",
"789_myfilename_file1", "101_novica_file2", "102_novica_file3"};
List<string> filesbyID = new List<string>();
List<string> filesbyName = new List<string>();
string theIDPattern = "123";
string theFileNamePattern = "myfilename";
foreach(var file in files)
{
//splitting the filename and checking by ID
if(file.Split('_')[0].Contains(theIDPattern))
{
filesbyID.Add(file);
}
//splitting the filename and checking by name
if (file.Split('_')[1].Contains(theFileNamePattern))
{
filesbyName.Add(file);
}
}
Result:
files by id:
123_novica_file1
123_novica_file3
123_novica_file2
files by name:
456_myfilename_file1
789_myfilename_file1

Performance recursive lookup function C#

We have the following recursive function which is used for looking up the member objects, which are listed in the following property of the group object. We use the group list for the recursive check in the groups.
This function with approximately 30k users and 40k groups takes about 20 minutes to run, which we want to speed up. Any ideas how to do this more efficient?
foreach (ad_group_source group in group_source)
{
List<ad_user_source> list = FindMembers(group, group_source, user_source);
}
public static List<ad_user_source> FindMembers(ad_group_source group, HashSet<ad_group_source> group_source, HashSet<ad_user_source> user_source)
{
List<String> members = group.Members.Split(';').ToList();
if (members.Equals(""))
{
return new List<ad_user_source>();
}
List<ad_user_source> members2 = new List<ad_user_source>();
foreach (String member in members)
{
if (!member.Equals(""))
{
Boolean isUser = false;
ad_user_source gebruiker = user_source.FirstOrDefault(u => u.DistinguishedName == member);
if (gebruiker != null)
{
members2.Add(gebruiker);
isUser = true;
}
if (!isUser)
{
ad_group_source group2 = group_source.FirstOrDefault(g => g.CN == member.Substring(3));
if (group2 != null)
{
List<ad_user_source> l = FindMembers(group2, group_source, user_source);
members2.AddRange(l);
}
}
}
}
List<ad_user_source> members3 = members2.Distinct().ToList();
return members3;
}
The problem is that your code keeps using hash sets as if they were lists. This is very inefficient.
To address this problem construct a Dictionary<string,ad_user_source> organized by DistinguishedName, and Dictionary<string,ad_group_source> organized by g.CN. Don't put groups with CN that is longer than three characters, in case there are any in the original set.

How to display unique items in an SQLite database to a Picker in C#

I have an assignment and am stock at populating items from a column in the SQLite database to a picker here is my code
from the database model
public IEnumerable<SingleSignerTable> GetItemList()
{
return _database.Query<SingleSignerTable>("SELECT * FROM [SingleSignerTable]");
}
from the front end
lCategory = new Label
{
Text = "Category",
FontAttributes = Font.SystemFontOfSize(5, FontAttributes.Bold).FontAttributes,
};
lField = new Picker { Title = "Category", VerticalOptions = LayoutOptions.Start };
lField.SelectedIndexChanged += lSport_SelectedIndexChanged;
FieldOption = new List<string> { "Others", GetItemList()};
foreach (string option in FieldOption)
{
lField.Items.Add(option);
};
private string GetItemList()
{
foreach (string option in FieldOption)
{
lField.Items.Add(option);
};
}
so that I can get these for example
Others
Baseball
Soccer
Volleyball
Scrabble
WWE
in the picker end
but the code doesn't seem to work
First, you should probably get rid of the second/private GetItemList method. Also don't name two different methods the same when posting as that makes it confusing. I would refactor your second method to something like:
var items = GetItemList().ToList();
foreach (var item in items)
{
lField.Items.Add(item.SomeStringPropertyOnSingleSignerTable);
};
or
var items = GetItemList().Select(x => x.SomeStringPropertyOnSingleSignerTable)
.Distinct()
.ToList();
foreach (string option in items)
{
lField.Items.Add(option);
};
As far as the error goes, it is because your method private string GetItemList() doesn't return a string but you declared that it does. I wouldn't name a method GetItemList if it returned only a string, it should probably return IEnumerable<T> or some kind of collection.

Categories