How to easily remove part of string from string array in c# - c#

I am using following code:
var names = ConfigurationManager.AppSettings.AllKeys.Where(k => k.StartsWith("name"));
and i get keys like: name1, name2, name16, name18.
Now i want to create another array which will remove name and just keep 1,2,16,18. Is there any easy way to do this in above code itself? Or do it seperatly?

You can directly
ConfigurationManager.AppSettings.AllKeys.Where(k => k.StartsWith("name")).Select(a => a.Replace("name",""));

I think your code is good enough. Just a little bit of performance improve by using substring as it's straightforward operation to remove prefix:
var prefix = "name"; // could be a parameter or used as const; just for example
var nums = ConfigurationManager.AppSettings.AllKeys.Where(s => s.StartsWith(prefix)).Select(s => s.Substring(prefix.Length)).ToArray();

Try this:
var names = ConfigurationManager.AppSettings.AllKeys.Where(k => k.StartsWith("name")).Select(p => p.Replace("name", ""));

Use:
var namesWithoutPrefix = names.Select(n => n.Substring(4));
Doing Replace instead of Substring might replace several substrings in one name (and is slower even if it doesn't do so).

I would not recommend relying on the position of the numeric value or the length of the string or the fact that the text reads 'name' at all. Instead you can use a simple regular expression to extract it consistently:
Regex regex = new Regex(#"[0-9]+");
var numbers = ConfigurationManager.AppSettings
.AllKeys.Select(p => regex.Match(p).Value).ToArray();

Related

Select String that is not a property of another object

I am writing code that will select string keys from an array ApiIds that are not property ApiId of results objects.
I wrote the following code, but it looks redundant to me, is there a way to combine this into one statement and not convert a HashSet of objects into another HashSet of Strings?
var resultsCached = new HashSet<string>(results.Select(x => x.ApiId));
var missingResults = apiIds.Select(x => !resultsCached.Contains(x));
Thanks.
Except will give you the items that aren't in the other collection:
var missingResults = apiIds.Except(results.Select(x => x.ApiId));
Another efficient O(n) approach is to use HashSet.ExceptWith which removes all elements from the set which are in the second sequence:
HashSet<string> apiIdSet = new HashSet<string>(apiIds);
apiIdSet.ExceptWith(results.Select(x => x.ApiId));
The set contains only strings which are not in results now.

How to store value from a IQueryable list to a string variable?

Hi my code is as below:
List<COSIS_DAL.PaymentsHeader> pheadr = c.GetPaymentHeaderByPayDate(PayDate);
public List<PaymentsHeader> GetPaymentHeaderByPayDate(DateTime payDate)
{
CosisEntities db = new CosisEntities();
IQueryable<PaymentsHeader> query = (from p in db.PaymentsHeaders
where p.PaymentDate.Value.Day == payDate.Day
&& p.PaymentDate.Value.Month == payDate.Month
&& p.PaymentDate.Value.Year == payDate.Year
select p);
return query.ToList();
}
so I want to save the data from pheadr to a string like this:
string keyword = Convert.ToString(pheadr.Select(m => m.VoucherNumber));
but I am not getting the value inside the list. Instead of the value I am getting this:
System.Linq.Enumerable+WhereSelectListIterator`2[COSIS_DAL.PaymentsHeader,System.String]
Please help me on this. I am really in trouble for this. Thanks in advance.
The problem is that pheadr.Select(m => m.VoucherNumber) isn't a single value... It's a collection of values... You could try:
string keyword = string.Join(", ", pheadr.Select(m => Convert.ToString(m.VoucherNumber)));
if you really want multiple voucher numbers separated by a ,.
or you could put it in a separate collection:
List<string> vouchers = pheadr.Select(m => Convert.ToString(m.VoucherNumber)).ToList();
Maybe something like this:
var keywords = pheadr.Select(x=>x.VoucherNumber.ToString()).ToList();
It will select all voucher numbers to list of strings. Is it what you wanted? keywords is List<string>
The string you are getting is because you are converting Linq expression to string, not inner field.
For only first record, use:
var keyword = Convert.ToString(pheadr.First().VoucherNumber);
If you are not sure that it will always return one value try:
var ph = pheadr.FirstOrDefault();
var keyword = ph!=null?Convert.ToString(ph.VoucherNumber):"";
EDIT:
as #xanatos suggested I used Convert instead ToString
Since pheadr is a collection of PaymentsHeader objects, the line
pheadr.Select(m => m.VoucherNumber)
will select each PaymentsHeader VoucherNumber property, which I'll assume is a string. So, the thing that will be returned will be a collection of strings. You can loop through it, you can cast it to a list or an array, or you can stick it in a stew, but you can't just call .ToString on it. That invokes the default object.ToString behaviour that just dumps the name of the class, which is what you got.
If you want to extract, for example, a comma-separated list of those strings, you can use:
string.Join(",", pheadr.Select(m => m.VoucherNumber))
try this
string keyword ;
if(pheader != null)
keyword = pheader.FirstOrDefault().VoucherNumber;
else
keyword = "";

How to remove specific url parameter in Regex?

I have this url pattern
http://dev.virtualearth.net/REST/v1/Locations?
addressLine={0}&
adminDistrict={1}&
locality={2}&
countryRegion={3}&
postalCode={4}&
userLocation={5}&
inclnb=1&
key={6}
Let us say that locality and userLocation have no values
http://dev.virtualearth.net/REST/v1/Locations?
addressLine=Main&
adminDistrict=WA&
locality=&
countryRegion=US&
postalCode=98001&
userLocation=&
inclnb=1&
key=BingKey
Then I want to remove all parameters that is equal to "&"
Like for example: 'locality=&' and 'userLocation=&'
And should be look like this:
http://dev.virtualearth.net/REST/v1/Locations?
addressLine=Main&
adminDistrict=WA&
countryRegion=US&
postalCode=98001&
inclnb=1&
key=BingKey
Final Output:
http://dev.virtualearth.net/REST/v1/Locations?addressLine=Main&adminDistrict=WA&countryRegion=US&postalCode=98001&inclnb=1&key=BingKey
Why do you specificly want to use regular expressions? There are some classes in C# specificly build for building and handling URIs. I suggest you look at HttpUtility.ParseQueryString() or Uri.TryCreate.
You would then parse the query string, loop through the variables that have only a key and no value, and reconstruct a new uri without them. It will be much easier to read and maintain than a regular expression.
Edit: I quickly decided to see how this could be done:
string originalUri = "http://www.example.org/etc?query=string&query2=&query3=";
// Create the URI builder object which will give us access to the query string.
var uri = new UriBuilder(originalUri);
// Parse the querystring into parts
var query = System.Web.HttpUtility.ParseQueryString(uri.Query);
// Loop through the parts to select only the ones where the value is not null or empty
var resultQuery = query.AllKeys
.Where(k => !string.IsNullOrEmpty(query[k]))
.Select(k => string.Format("{0}={1}", k, query[k]));
// Set the querystring part to the parsed version with blank values removed
uri.Query = string.Join("&",resultQuery);
// Done, uri now contains "http://www.example.org/etc?query=string"
#"[\w]+=\&" should get you what you are looking for, but wouldn't it be easier to simply not add the parameter to the url string if the corresponding value is empty?

c# string.replace in foreach loop

Somehow I can't seem to get string replacement within a foreach loop in C# to work. My code is as follows :
foreach (string s in names)
{
s.Replace("pdf", "txt");
}
Am still quite new to LINQ so pardon me if this sounds amateurish ;)
You say you're after a LINQ solution... that's easy:
var replacedNames = names.Select(x => x.Replace("pdf", "txt"));
We don't know the type of names, but if you want to assign back to it you could potentially use ToArray or ToList:
// If names is a List<T>
names = names.Select(x => x.Replace("pdf", "txt")).ToList();
// If names is an array
names = names.Select(x => x.Replace("pdf", "txt")).ToArray();
You should be aware that the code that you've posted isn't using LINQ at all at the moment though...
Strings in C# are immutable (does not change), so s.Replace will return a new string. Unfortunately this means you cannot use foreach to do the update. If names is an array this should work:
for(int i = 0; i < names.Length; i++)
{
names[i] = names[i].Replace("pdf", "txt");
}
As others have mentioned you'd need to use a for loop to do this in-place. However, if you don't need the operation to be done in-place (i.e. the results can be a different collection), then you could also do it as a linq query, e.g.
var results = from name in names select name.Replace("pdf", "txt");
One thing though - it looks like you are trying to change the extension of some file names. If that's what you are trying to do then I'd recommend Path.ChangeExtension which is specifically designed for this purpose.
var results = from name in names select Path.ChangeExtension(name, "txt");
s.Replace is a function so you would like s=s.Replace().. although it's better to use StringBuilder. (see upper answer)
Why use replace? It will make the application slow. Use regex instead:
http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.replace.aspx

How to make a C# 'grep' more Functional using LINQ?

I have a method that performs a simplistic 'grep' across files, using an enumerable of "search strings". (Effectively, I'm doing a very naive "Find All References")
IEnumerable<string> searchStrings = GetSearchStrings();
IEnumerable<string> filesToLookIn = GetFiles();
MultiMap<string, string> references = new MultiMap<string, string>();
foreach( string fileName in filesToLookIn )
{
foreach( string line in File.ReadAllLines( fileName ) )
{
foreach( string searchString in searchStrings )
{
if( line.Contains( searchString ) )
{
references.AddIfNew( searchString, fileName );
}
}
}
}
Note: MultiMap<TKey,TValue> is roughly the same as Dictionary<TKey,List<TValue>>, just avoiding the NullReferenceExceptions you'd normally encounter.
I have been trying to put this into a more "functional" style, using chained LINQ extension methods but haven't figured it out.
One dead-end attempt:
// I get lost on how to do a loop within a loop here...
// plus, I lose track of the file name
var lines = filesToLookIn.Select( f => File.ReadAllLines( f ) ).Where( // ???
And another (hopefully preserving the file name this time):
var filesWithLines =
filesToLookIn
.Select(f => new { FileName = f, Lines = File.ReadAllLines(f) });
var matchingSearchStrings =
searchStrings
.Where(ss => filesWithLines.Any(
fwl => fwl.Lines.Any(l => l.Contains(ss))));
But I still seem to lose the information I need.
Maybe I'm just approaching this from the wrong angle? From a performance standpoint, the loops ought to perform in roughly the same order as the original example.
Any ideas of how to do this in a more compact functional representation?
How about:
var matches =
from fileName in filesToLookIn
from line in File.ReadAllLines(fileName)
from searchString in searchStrings
where line.Contains(searchString)
select new
{
FileName = fileName,
SearchString = searchString
};
foreach(var match in matches)
{
references.AddIfNew(match.SearchString, match.FileName);
}
Edit:
Conceptually, the query turns each file name into a set of lines, then cross-joins that set of lines to the set of search strings (meaning each line is paired with each search string). That set is filtered to matching lines, and the relevant information for each line is selected.
The multiple from clauses are similar to nested foreach statements. Each indicates a new iteration in the scope of the previous one. Multiple from clauses translate into the SelectMany method, which selects a sequence from each element and flattens the resulting sequences into one sequence.
All of C#'s query syntax translates to extension methods. However, the compiler does employ some tricks. One is the use of anonymous types. Whenever 2+ range variables are in the same scope, they are probably part of an anonymous type behind the scenes. This allows arbitrary amounts of scoped data to flow through extension methods like Select and Where, which have fixed numbers of arguments. See this post for further details.
Here is the extension method translation of the above query:
var matches = filesToLookIn
.SelectMany(
fileName => File.ReadAllLines(fileName),
(fileName, line) => new { fileName, line })
.SelectMany(
anon1 => searchStrings,
(anon1, searchString) => new { anon1, searchString })
.Where(anon2 => anon2.anon1.line.Contains(anon2.searchString))
.Select(anon2 => new
{
FileName = anon2.anon1.fileName,
SearchString = anon2.searchString
});
I would use the FindFile (FindFirstFileEx, FindNextFile, etc, etc) API calls to look in the file for the term that you are searching on. It will probably do it faster than you reading line-by-line.
However, if that won't work for you, you should consider creating an IEnumerable<String> implementation which will read the lines from the file and yield them as they are read (instead of reading them all into an array). Then, you can query on each string, and only get the next one if it is needed.
This should save you a lot of time.
Note that in .NET 4.0, a lot of the IO apis that return lines from files (or search files) will return IEnumerable implementations which do exactly what is mentioned above, in that it will search directories/files and yield them when appropriate instead of front-loading all the results.

Categories