I've an array. Let's say;
private string[] WhiteList =
{
"abcxyz.cs",
"mouseapi.dll",
"SensitivtyFix.asi",
"drake.mp3"
};
Now I want to exclude that array from a directory/file search. How do I achieve that?
For this search, I'm using another array called BlackList from which I could fetch desired files but I'm unable to exclude files from the array Whitelist.
for (int i = 0; i < GetSize; ++i)
{
foreach (var File in DirInf.GetFiles("*", SearchOption.AllDirectories))
{
if (File.FullName.Contains(Blacklist[i]) && !File.FullName.Contains(WhiteList[i]))
{
listBox1.Items.Add("File: " + File.FullName);
}
}
}
The condition you need (for use with LINQ Where function) is
Predicate<FileInfo> filter =
f => Array.Exists(blackList, f.FullName.Contains) &&
!Array.Exists(whiteList, f.FullName.Contains);
The problem with your original code is that it looked at blackList[i] and whiteList AT THE SAME i, but the list index that matches might be different.
Now you may fill your list box:
foreach (var file in DirectoryInfo.GetFiles("*", SearchOption.AllDirectories).Where(filter))
listBox1.Items.Add(file);
YOu need
if (BlackList.Contains(File.FullName) && !WHiteList.Contains(File.FullName)))
although that seems odd, since you can just not put the whitelist names in the blacklist. Maybe you need || not &&
Related
How can I delete the current element of an array inside a foreach-loop?
My program gets data form a DB and sends it to a new one via HTTP requests. Now I want to post a JSON string to my new DB. If it was a success I want to delete the current array item which I'm working with. Something like this.
foreach(var item in array)
{
bool decide = method.DoSomething();
if(decide == true)
{
//delete current item
}
}
since you cannot delete items from an array and change the size of it here is a loop approach using a second collection
List<itemClass> keepCollection = new List<itemClass>();
foreach(var item in array)
{
bool decide = method.DoSomething();
if(decide == false)
{
keepCollection.Add(item);
}
}
If you need it again in array form just call ToArray()
var finalResult = keepCollection.ToArray();
appraoch with Linq which creates a new array with valid elements and overwrites the existing array
array = array.Where(x => !method.DoSomething(x)).ToArray(); //select valid elements
there are 2 ways (both were tested)
foreach (var item in array.ToList())
{
bool decide = method.DoSomething();
if (decide == true)
{
item.Remove();
}
}
and
for ( i=0; i < array.Length; i++)
{
bool decide = method.DoSomething();
if (decide == true)
{
array[i].Remove();
}
}
Whenever you want to delete entries from a collection, you should never loop through that collection from beginning to end, but always from end back to beginning.
By the way, C# does not allow you deleting entries from a collection while looping through that collection using a foreach loop.
I have code that will create an array of all XML element values called "TrackFileId":
XDocument cpldoc = XDocument.Load(cplsource);
var cpltfid = cpldoc.Descendants(cplns + "TrackFileId").ToArray();
I then need to recursively search a number of parent directories (max 3 levels up) for any files called "ASSETMAP.xml", and parse them for any elements with matching values from the array.
I haven't figured out how to specify [n] number of directories from the starting directory (variable "folder") yet. However, here is how I just find the ASSETMAP just looking in the same directory as "folder", which works:
string assetmap = Directory.GetFiles(folder, "*ASSETMAP*")[0].ToString();
Once I have found all ASSETMAP.xml docs, I need to loop through each "Id" element within them to find any matching values from the array, but I can't get it to work, as it seems to just look for the first item in the array and give up. In this case, the first value in the array is not a match, so the bool is false.
XDocument assetmapdoc = XDocument.Load(assetmap);
bool cpltfidfound = false;
foreach (var assetC in assetElements)
{
var innerElementsC = assetC.Descendants(assetns + "Id").First();
if (!innerElementsC.Value.Equals(cpltfid))
continue;
cpltfidfound = true;
}
if (cpltfidfound)
{
//do something
}
SOLVED
The key was Array.Exists . I haven't added the recursive search yet, but this will handle the array search:
foreach (var assetC in assetElements)
{
var innerElementsC = assetC.Descendants(assetns + "Id").FirstOrDefault().Value;
if (Array.Exists(cpltfids, element => element.Value == (innerElementsC)))
{
MessageBox.Show("MATCH");
}
else
{
MessageBox.Show("NO MATCH");
}
I try to explain my problem:
Okay, I need the KSCHL and the Info.
I need the KSCHL from the result file and then I want to search after the KSCHL in the other file "Data".
In the first file I have all KSCHL.
var kschlResultList = docResult.SelectNodes(...);
var kschlDataList = docData.SelectNodes(...);
var infoDataList = docData.SelectNodes(...);
for (int i = 0; i < kschlResultList.Count; i++)
{
string kschlResult = kschlResultList[i].InnerText;
for (int x = 0; x < kschlDataList.Count; x++)
{
string kschlData = kschlDataList[x].InnerText;
if (kschlData == kschlResult)
{
for (int y = 0; y < infoDataList.Count; y++)
{
string infoData = infoDataList[y].InnerText;
if (infoData == kschlResult)
{
//I know the If is false
string infoFromKschl = infoData;
}
}
}
}
}
The problem is now to find the KSCHL (from the first file) in the second file and then to search after the "info".
So if I have the KSCHL "KVZ1" in the first file, then I want to search this KSCHL in the second file and the associated Info for it.
Hope you understand :)
You don't have to loop quite so much. :-)
Using XPath - the special strings inside SelectNodes() or SelectSingleNode(), you can go pretty directly to what you want.
You can see a great basic example - several really - of how to select an XML node based on another node at the same level here:
How to select a node using XPath if sibling node has a specific value?
In your case, we can get to a list of the INFO values more simply by looping just through the KSCHL values. I use them as text, because I want to make a new XPath string with them.
I'm not clear exactly what format you want the results in, so I'm simply pushing them into a SortedDictionary for now.
At that last step, you could do other things as is most useful to you..... such as push them into a database, dump them in a file, send them to another function.
/***************************************************************
*I'm not sure how you want to use the results still,
* so I'll just stick them in a Dictionary for this example.
* ***********************************************************/
SortedDictionary<string, string> objLookupResults = new SortedDictionary<string, string>();
// --- note how I added /text()... doesn't change much, but being specific <<<<<<
var kschlResultList = docresult.SelectNodes("//root/CalculationLogCompact/CalculationLogRowCompact/KSCHL/text()");
foreach (System.Xml.XmlText objNextTextNode in kschlResultList) {
// get the actual text from the XML text node
string strNextKSCHL = objNextTextNode.InnerText;
// use it to make the XPath to get the INFO --- see the [KSCHL/text()= ...
string strNextXPath = "//SNW5_Pricing_JKV-Q10_full/PricingProcedure[KSCHL/text()=\"" + strNextKSCHL + "\" and PRICE>0]/INFO/text()";
// and get that INFO text! I use SelectSingleNode here, assuming only one INFO for each KSCHL..... if there can be more than one INFO for each KSCHL, then we'd need another loop here
string strNextINFO = docdata.SelectSingleNode(strNextXPath)?.InnerText; // <<< note I added the ? because now there may be no result with the rule PRICE>0.
// --- then you need to put this result somewhere useful to you.
// I'm not sure what that is, so I'll stick it in the Dictionary object.
if (strNextINFO != null) {
objLookupResults.Add(strNextKSCHL, strNextINFO);
}
}
I have a program that checks two text files for a specific field then checks to see if either file has the specified field. If it does then the number of matches is stored into another List. The problem I am having is that it is only writing the first match to the text file, when I know I have two matches. I am fairly new to C# so any help/advice would be appreciated, the code below is doing the check.
while ((lineBeingRead = fileToRead.ReadLine()) != null)
{
if (lineBeingRead.IndexOf(" :22:", 0) == 0)
{
lstTwentyOneCounter.Add(lineBeingRead.Substring(11));
lstStoreTwentyOne = lstTwentyOneCounter;
}
}
The code below is writing to the text file.
foreach (var single103 in lstStore103)
{
foreach (var single101 in lstStore101)
{
if (single101 == single103)
{
checkResults.Add(single103);
System.IO.File.WriteAllText(#"H:\Compare.txt", single103);
break;
}
}
}
Thanks,
Ryan
WriteAllText will overwrite the existing file - so only a single entry will appear to be written.
You will want to append or write all instead.
System.IO.File.Delete(#"H:\Compare.txt");
foreach (var single103 in lstStore103)
{
foreach (var single101 in lstStore101)
{
if (single101 == single103)
{
checkResults.Add(single103);
System.IO.File.AppendAllText(#"H:\Compare.txt", single103 + Environment.NewLine);
}
}
}
or (if neither lstStore103 nor lstStore101 have duplicates):
System.IO.File.Delete(#"H:\Compare.txt");
foreach (var value in lstStore103.Intersect(lstStore101))
{
checkResults.Add(value);
System.IO.File.AppendAllText(#"H:\Compare.txt", value + Environment.NewLine);
}
The break; is responsible, it will leave the loop.
But you also don't want to use WriteAllText which rewrites the whole text-file but you want to append a new line. I would use this approach:
string startPattern = " :22:";
List<string> lstStoreTwentyOne = File.ReadLines(path)
.Where(l => l.StartsWith(startPattern))
.Select(l => l.Substring(startPattern.Length))
.ToList();
This will create and fill the list. I don't know how this is related to the lstStore103-list.
However, this will write all to the text-file and replaces your loops:
var matchingItems = lstStore103.Intersect(lstStore101);
File.WriteAllLines(#"H:\Compare.txt", matchingItems);
New to c# and ASP.net, I am working on retrieving Directories and have done so.
{
public partial class WebForm1 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
ListItem item;
ListItem item
string folderLocation = #"\\serv5007i\TeamCityDeploy\Trunk Production Build\Current\bin\Runtime";
int startSize = folderLocation.Length+1;
string[] fileNames = Directory.GetDirectories(folderLocation);
foreach (string fileName in fileNames)
{
item = new ListItem();
item.Value = item.Text = "Add " + fileName.Substring(startSize);
CheckBoxList1.Items.Add(item);
CheckBoxList2.Items.Add(item);
CheckBoxList3.Items.Add(item);
}
}
}
}
So I have the output as the Directory of 15 or so folders. Is it possible to return only 10 and then 5 in another div.
So basically I have 15 folders being returned, but I need to have the bottom 5 under a different heading to the others. My apologies if I'm not being clear. Beginner!
You can control the output, when you execute Directory.GetDirectories you'll receive a collection. I believe in this instance, you'll receive a string array. This can be manipulated however you want:
Loop Example's:
foreach(string directory in directories)
{
// Enumerate over all items within the collection.
}
for(int index = 0; index < directories.Length; index++)
{
// Will enumerate until index == directories
// If you make index five, it would start at position six of the array.
// since they're zero based. But you can manipulate how you want.
}
do
{
index++
// Perform an action. Based on the while.
}
while(index != directories.Length);
while(index != directories)
{
index++;
// Perform action until equal.
}
The downfall to these approaches, are you're manipulating a integer for a starting position or ending position. Which can create confusion in the code. The other approach would be Linq, which similar to the above as far as iteration but will make the code a bit more expressive.
Linq Example's:
var filtered = directories.Take(10); // Take the first ten.
var filtered = directories.Skip(5); // Skip the first five.
var filtered = directories.Where(path => new DirectoryInfo(path).Name.Contains("Name")); // If directory names contain, return on that.
You could also do:
var filter = Directory.EnumerateDirectories(path)
.Where(directory => directory.Name.Contains("Sample"))
.Take(10);
So the initial line will automatically enumerate the directories within the provided path, you filter based on name, then take the first ten.
You can tackle this problem a lot of different ways, that is why narrowing it down would be more helpful.
"Go not to the Elves for counsel, for they will say both no and yes."
Update:
A full Linq example would be one of these two approaches:
var directories = Directory.GetDirectories(path);
var filtered = directories.Skip(5);
Or you could do it in a single line.
var filtered = Directory.EnumerateDirectories(path).Skip(5).Take(5);