Reputation: 93
I have a string that has all the available partition letters for allocation.
I want to delete each character (or drive letter) that is already in use from this string.
I have tried doing this:
string allletters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
DriveInfo[] d = DriveInfo.GetDrives();
string notusedletters = string.Empty;
foreach (DriveInfo drive in AllDrives)
{
string driveLetterOnly = (drive.Name).Replace(@":\", ""); // remove ":\" characters from the drive letter
notusedletters = allletters.Replace(driveLetterOnly, ""); // remove driveLetterOnly from the allletters string.
}
But notusedletters string always returns the initial value of allletters (ABCDEFGHIJKLMNOPQRSTUVWXYZ).
What's wrong with this code?
Upvotes: 0
Views: 99
Reputation: 7054
When you call a Replace
on allletters
a new string will be created. Replace
does not modify exists string.
To make your code work you should re-assign allletters
on each iteration:
allletters = allletters.Replace(....)
Or just use this single line linq query:
string allletters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string notusedletters = new string(
allletters.Except(
DriveInfo.GetDrives().Select(d => d.Name[0])
).ToArray());
It should be noted that Except does not guarantee that the order is preserved
I've checked this answer and it says that Except
preserves order. To make sure I've decompiled System.Core
Please see implementation of Except
with my comments:
public static IEnumerable<TSource> Except<TSource>(
this IEnumerable<TSource> first,
IEnumerable<TSource> second)
{
// I removed a null checks
return Enumerable.ExceptIterator<TSource>(first, second,
(IEqualityComparer<TSource>) null);
}
private static IEnumerable<TSource> ExceptIterator<TSource>(
IEnumerable<TSource> first,
IEnumerable<TSource> second,
IEqualityComparer<TSource> comparer)
{
Set<TSource> set = new Set<TSource>(comparer);
foreach (TSource source in second)
set.Add(source);
foreach (TSource source in first)
{
if (set.Add(source))
yield return source; // elements will be yielded in same order
// as they appear in first sequence
}
}
But to be 100% sure that behavior will not change in future you can use OrderBy
as @ckuri suggested in comment:
string notusedletters = new string(
allletters.Except(
DriveInfo.GetDrives().Select(d => d.Name[0])
)
.OrderBy(c => c) // explicit ordering
.ToArray()
);
Upvotes: 2
Reputation: 2439
Do not use notusedletters
or just keep the same string while using the replace
.
string allletters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
DriveInfo[] d = DriveInfo.GetDrives();
foreach (DriveInfo drive in d)
{
string driveLetterOnly = (drive.Name).Replace(@":\", ""); // remove ":\" characters from the drive letter
allletters = allletters.Replace(driveLetterOnly, ""); // remove driveLetterOnly from the allletters string.
}
Console.WriteLine(allletters);
Upvotes: 1