Reputation: 87
I have a in C# a String[]
with a list of folders. And I want to get a sublist depending on a criteria. For example:
var folder_list = new String[] {
"FOLDER0001",
"FOLDER0002",
"FOLDER0003",
"FOLDER0004",
"FOLDER0005"
};
and with parameters (from and to) get the sublist
For example
from:1
to:3
I wish to get String[] sub_list = {"FOLDER0001", FOLDER0002", "FOLDER0003"}
I would very much like to do it using linq.
Upvotes: 0
Views: 931
Reputation: 87
thank you very much everyone for the responses. Sorry for my english :(
I may not explain the problem correctly ... Basically I receive a fixed list of folders that I must compress and send by email. Because the SMTP server has attachment size limitations, I am forced to split the folder list into multiple zip files, But folders LIST may not be consecutive. Example:
var folder_list = new String[] {
"ABCDEF000001",
"ABCDEF000002",
"ABCDEF000004",
"ABCDEF000005",
"ABCDEF000007",
};
So if I want the list from 1 to 3 I should get "ABCDEF000001", "ABCDEF000002"
My solution is similar to the one I implement Harald and John Wu
private String[] get_sub_list_folders(Int32 since, Int32 to, String[] folder_list)
{
var result = from folder in folder_list
where (Int32.Parse(folder.Substring(8)) >= since && Int32.Parse(folder.Substring(8)) <= to)
select folder;
return (result.ToList().ToArray());
}
private void zip_folders()
{
const String folder_pattern = "ABCDEF";
const Int32 folders_in_zip = 5000;
// Create list of all folder
String[] folder_list = Directory.GetDirectories(".", folder_pattern + "*", SearchOption.TopDirectoryOnly);
// Just in case order by name
Array.Sort(folder_list);
Int32 folders_count = folder_list.Length;
Int32 from = 1;
Int32 to = folders_in_zip;
// Build a chunk of the folder list
while (folders_count > 0)
{
// Make a subset fixed folder list
String[] zip_folders_list = get_sub_list_folders(from, to, folder_list);
// Build zip name
String zip_name = String.Format("{0}{1:0000000}_{0}{2:0000000}.zip", folder_pattern, from, to);
// Create zip
zip.create(zip_folders_list, zip_name);
from += folders_in_zip;
to += folders_in_zip;
folders_count -= folders_in_zip;
}
}
Upvotes: 0
Reputation: 30454
For every folder name, extract the key, parse the key to a number and keep only the folder name if the number is between min and max
Using extension methods. See extension methods demystified
public string ExtractKeyText(this string folderName)
{
// TODO: decide what to do if folderName == null
// depending on your actual folder name.
// is it really just "Folder00001" etc?
return folderName.SubString(6);
// if more difficult folderNames, consider using Regular Expressions
}
public IEnumerable<string> WhereFolderKeyBetween(
this IEnumerable<string> folders,
int minKey,
int maxKey)
{
// TODO: decide what to do if folders == null, or minKey > maxKey
return folders.Where(folder =>
{
string keyTxt = folder.ExtractKeyText();
return int.TryParse(keyTxt, out int key)
&& minKey <= key && key <= maxKey;
});
};
Usage:
IEnumerable<string> folderNames = ...
IEnumerable<string> folderNamesWithinRange = folderNames.WhereFolderKeyBetween(3, 7);
Upvotes: 1
Reputation: 26907
Since you have a range to index you can use that with LINQ to extract the elements:
var sublist = Enumerable.Range(from-1, to-from+1).Select(i => folder_list[i]).ToArray();
But it would be much more efficient to use ArraySegment
instead:
var sl = new ArraySegment<string>(folder_list, from-1, to-from+1).ToArray();
Upvotes: 0
Reputation: 52210
You'd need to use the integer input to reproduce the matching string(s) in order to search the strings by range.
var folder_list = new String[] {
"FOLDER0001",
"FOLDER0002",
"FOLDER0003",
"FOLDER0004",
"FOLDER0005"
};
string[] GetSublist(int from, int to)
{
string start = "FOLDER" + from.ToString("D4");
string end = "FOLDER" + to.ToString("D4");
return folder_list.Where( x => (x >= start && x <= end)).ToArray();
}
Another option is to change the way you store the data to make it more searchable. This would perform slightly better and be more resilient to changes in the string formatting.
var folder_list = new Dictionary<int,string> {
{ 1, "FOLDER0001"},
{ 2, "FOLDER0002"},
{ 3, "FOLDER0003"},
{ 4, "FOLDER0004"},
{ 5, "FOLDER0005"}
};
string[] GetSublist(int from, int to)
{
return folder_list
.Where
(
x => (x.Key >= from && x.Key <= to)
)
.Select( x => x.Value )
.ToArray();
}
Upvotes: 1
Reputation: 22079
Linq has the Skip
method to leave out a number of elements in a sequence and Take
to get a number of elements. The number that you pass is the count of elements that should be skipped or taken. For your example:
String[] subArray = folder_list.Take(3).ToArray();
You can also generalize this. Since you identify the first element with 1
instead of 0
, the query would look like this.
public String[] SubArray(String[] array, int from, int to)
{
return array.Skip(from - 1).Take(to).ToArray();
}
Upvotes: 2