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);
Related
I have two var of code:
first:
struct pair_fiodat {string fio; string dat;}
List<pair_fiodat> list_fiodat = new List<pair_fiodat>();
// list filled 200.000 records, omitted.
foreach(string fname in XML_files)
{
// get FullName and Birthday from file. Omitted.
var usersLookUp = list_fiodat.ToLookup(u => u.fio, u => u.dat); // create map
var dates = usersLookUp[FullName];
if (dates.Count() > 0)
{
foreach (var dt in dates)
{
if (dt == BirthDate) return true;
}
}
}
and second:
struct pair_fiodat {string fio; string dat;}
List<pair_fiodat> list_fiodat = new List<pair_fiodat>();
// list filled 200.000 records, omitted.
foreach(string fname in XML_files)
{
// get FullName and Birthday from file. Omitted.
var members = from s in list_fiodat where s.fio == FullName & s.dat == Birthdate select s;
if (members.Count() > 0 return true;
}
They make the same job - searching user by name and birthday.
The first one work very quick.
The second is very slowly (10x-50x)
Tell me please if it possible accelerate the second one?
I mean may be the list need in special preparing?
I tried sorting: list_fiodat_sorted = list_fiodat.OrderBy(x => x.fio).ToList();, but...
I skip your first test and change Count() to Any() (count iterate all list while any stop when there are an element)
public bool Test1(List<pair_fiodat> list_fiodat)
{
foreach (string fname in XML_files)
{
var members = from s in list_fiodat
where s.fio == fname & s.dat == BirthDate
select s;
if (members.Any())
return true;
}
return false;
}
If you want optimize something, you must leave comfortable things that offer the language to you because usually this things are not free, they have a cost.
For example, for is faster than foreach. Is a bit more ugly, you need two sentences to get the variable, but is faster. If you iterate a very big collection, each iteration sum.
LINQ is very powerfull and it's wonder work with it, but has a cost. If you change it for another "for", you save time.
public bool Test2(List<pair_fiodat> list_fiodat)
{
for (int i = 0; i < XML_files.Count; i++)
{
string fname = XML_files[i];
for (int j = 0; j < list_fiodat.Count; j++)
{
var s = list_fiodat[j];
if (s.fio == fname & s.dat == BirthDate)
{
return true;
}
}
}
return false;
}
With normal collections there aren't difference and usually you use foeach, LINQ... but in extreme cases, you must go to low level.
In your first test, ToLookup is the key. It takes a long time. Think about this: you are iterating all your list, creating and filling the map. It's bad in any case but think about the case in which the item you are looking for is at the start of the list: you only need a few iterations to found it but you spend time in each of the items of your list creating the map. Only in the worst case, the time is similar and always worse with the map creation due to the creation itself.
The map is interesting if you need, for example, all the items that match some condition, get a list instead found a ingle item. You spend time creating the map once, but you use the map many times and, in each time, you save time (map is "direct access" against the for that is "sequencial").
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'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 &&
I have an ArrayList with multiples items on it, everyone of them is a String divided by commas "loglogs", the three first items are the localization (Destin, lat and long). I need to insert the Strings of these loglogs in buttons depending on its localization (based on that three parameters) in the button Tooltip or text programatically. I have all the button creation but I have to add the strings but there are more loglogs than buttons so...
I need to "filter" the ArrayList into another ArrayList, filter it depending on these three inital coordinates, I want to create another ArrayList but appending the strings that are identical in their three first elements of the arrayList. That way I will combine the "loglogs" into another "loglogsCondensed", with all the "localization" unique so I can add this part to my button and index creation.
foreach (String log in logslogs)
{
String[] colContent = log.Split(','); //splited the content with commas
Loglog log = new Loglog(); //Loglog is a class of logs with information in specific columns
log.Destin = colContent[0];
log.Lat = Convert.ToChar(colContent[1]);
log.Long = colContent[2];
log.Barcode = colContent[6];
log.Source = colContent[7];
log.SampleName = colContent[9];
AllLogs.Add(log);
I need to pass from logslogs with 1000 memebers to an ArrayList with less items, where the ones with the same location based on the three first items are appended as one item.
Suposse this is kind of easy if you know how to code properly (not my case). A thousand thanks only for read this out, even more to the people who try to help.
Best,
I have the solution!, probably is not going to win any contest of cleaneness but it does what I need!. I create an index to filter comparing the items depending of the three coordinates: Destin, Long and Lat. If they are the same I remove the last item and put the appended line in the last place and so on...
int c = 0; //Just to go the first time
//We create an index to compare the former with the "actual"
//log in every loop of the "foreach"
String IndiceDestin0 = string.Empty;
String IndiceLat0 = string.Empty;
String IndiceLong0 = string.Empty;
String IndiceDestin1;
String IndiceLat1;
String IndiceLong1;
foreach (String log in logslogs)
{
String[] LongContent = log.Split(',');
Loglog log = new Loglog();
log.Destin = LongContent[0];
log.Lat = Convert.ToChar(LongContent[1]);
log.Long = LongContent[2];
log.Barcode = LongContent[6];
log.Source = LongContent[7];
log.DestDestinBarcode = LongContent[8];
log.SampleName = LongContent[9];
AllLogs.Add(log);
//This only works once, the first time because we don't have a "former" data to compare we have to bypass the comparison
if (c == 0)
{
IndiceDestin0 = LongContent[0];
IndiceLat0 = LongContent[1];
IndiceLong0 = LongContent[2];
c++;
}
else
{
IndiceDestin1 = LongContent[0];
IndiceLat1 = LongContent[1];
IndiceLong1 = LongContent[2];
if (IndiceDestin0.Equals(IndiceDestin1) && IndiceLat0.Equals(IndiceLat1) && IndiceLong0.Equals(IndiceLong1))
{
int last = logsToButtons.Count - 1;
string oldLog = logsToButtons[last].ToString();
string appendedLog = oldLog + log;
//We remove the last "single" log to add the aggregated log
logsToButtons.RemoveAt(last);
logsToButtons.Add(appendedLog);
}
else
{
logsToButtons.Add(log);
}
IndiceDestin0 = IndiceDestin1;
IndiceLat0 = IndiceLat1;
IndiceLong0 = IndiceLong1;
c++;
}
}
I get to have a shorter version of the array but appending together the ones that have the same coordenates, thank you everybody for your help, I know is messy but it works!
Best,
I'm using the Linq OrderBy() function to sort a generic list of Sitecore items by display name, then build a string of pipe-delimited guids, which is then inserted into a Sitecore field. The display name is a model number of a product, generally around 10 digits. At first it seemed like this worked 100% of the time, but the client found a problem with it...
This is one example that we have found so far. The code somehow thinks IC-30R-LH comes after IC-30RID-LH, but the opposite should be true.
I put this into an online alphabetizer like this one and it was able to get it right...
I did try adding StringComparer.InvariantCultureIgnoreCase as a second parameter to the OrderBy() but it did not help.
Here's the code... Let me know if you have any ideas. Note that I am not running this OrderBy() call inside of a loop, at any scope.
private string GetAlphabetizedGuidString(Item i, Field f)
{
List<Item> items = new List<Item>();
StringBuilder scGuidBuilder = new StringBuilder();
if (i != null && f != null)
{
foreach (ID guid in ((MultilistField)f).TargetIDs)
{
Item target = Sitecore.Data.Database.GetDatabase("master").Items.GetItem(guid);
if (target != null && !string.IsNullOrEmpty(target.DisplayName)) items.Add(target);
}
// Sort it by item name.
items = items.OrderBy(o => o.DisplayName, StringComparer.InvariantCultureIgnoreCase).ToList();
// Build a string of pipe-delimited guids.
foreach (Item item in items)
{
scGuidBuilder.Append(item.ID);
scGuidBuilder.Append("|");
}
// Return string which is a list of guids.
return scGuidBuilder.ToString().TrimEnd('|');
}
return string.Empty;
}
I was able to reproduce your problem with the following code:
var strings = new string[] { "IC-30RID-LH", "IC-30RID-RH", "IC-30R-LH", "IC-30R-RH"};
var sorted = strings.OrderBy(s => s);
I was also able to get the desired sort order by adding a comparer to the sort.
var sorted = strings.OrderBy(s => s, StringComparer.OrdinalIgnoreCase);
That forces a character-by-character (technically byte-by-byte) comparison of the two strings, which puts the '-' (45) before the 'I' (73).