In C# what would you consider the fastest way to do this? The code will ultimately be part of a SQL Server CLR C# user defined function, but I don't think that is important for this question.
INPUT: "1,3,2,5,4"
OUTPUT: "1,2,3,4,5"
The sorting has to be done by comparing the numbers as ints, not strings or chars.
I currently have the following but it is sorting based on strings, not ints. I could introduce a custom comparer but figure I would ask the question to see if others have any ideas before I do that.
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlString udfSortDimensionValueIDString(SqlString DimensionValueIDs)
{
string[] values = ((string)DimensionValueIDs).Split(',');
Array.Sort(values);
return String.Join(",", values);
}
Using .NET 3.5 if that matters.
You can use Linq:
using System.Linq; // no include required, just uses the namespace
...
String Input = "1,3,2,5,4";
String Output = String.Join(",", Input
.Split(',')
.Select(x => int.Parse(x))
.OrderBy(x => x));
string s = "1,3,2,5,4";
string ordered = String.Join(",", s.Split(',').Select(c => Convert.ToInt32(c)).OrderBy(i=>i));
You can split the string on the commas and convert each string to a number using the Convert library. http://msdn.microsoft.com/en-us/library/bb397679.aspx
Related
I have an XML instance that contains processing instructions. I want a specific one (the schematron declaration):
<?xml-model href="../../a/b/c.sch" schematypens="http://purl.oclc.org/dsdl/schematron"?>
There may or may not be more than these very processing instructions present, so I can't rely on its position in the DOM; it is guaranteed, on the other hand, that there will be only one (or none) such Schematron file reference. Thus, I get it like so:
XProcessingInstruction p = d.Nodes().OfType<XProcessingInstruction>()
.Where(x => x.Target.Equals("xml-model") &&
x.Data.Contains("schematypens=\"http://purl.oclc.org/dsdl/schematron\""))
.FirstOrDefault();
In the example given, the content of p.Data is the string
href="../../a/b/c.sch" schematypens="http://purl.oclc.org/dsdl/schematron"
I need to extract the path specified via #href (i. e. in this example I would want the string ../../a/b/c.sch) without double quotes. In other words: I need the substring after href=" and before the next ". I'm trying to achieve my goal with LINQ:
var a = p.Data.Split(' ').Where(s => s.StartsWith("href=\""))
.Select(s => s.Substring("href=\"".Length))
.Select(s => s.TakeWhile(c => c != '"'));
I would have thought this gave me a IEnumerable<char> which I could then convert to a string in one of the ways described here, but that's not the case: According to LINQPad, I seem to be getting a IEnumerabale<IEnumerable<char>> which I can't manage to make into a string.
How could this be done correctly using LINQ? Maybe I'd better be using Regex within LINQ?
Edit: After typing this down, I came up with a working solution, but it seems very inelegant:
string a = new string
(
p.Data.Substring(p.Data.IndexOf("href=\"") + "href=\"".Length)
.TakeWhile(c => c != '"').ToArray()
);
What would be a better way?
Try this:
var input = #"<?xml-model href=""../../a/b/c.sch"" schematypens=""http://purl.oclc.org/dsdl/schematron""?>";
var match = Regex.Match(input, #"href=""(.*?)""");
var url = match.Groups[1].Value;
That gives me ../../a/b/c.sch in url.
Please don't use Regex for general XML parsing, but for this situation it's fine.
I need to find distinct values of partial filenames in an array of filenames. I'd like to do it in one line.
So, I have something like that as a filenames:
string[] filenames = {"aaa_ab12345.txt", "bbb_ab12345.txt", "aaa_ac12345.txt", "bbb_ac12345"}
and I need to find distinct values for ab12345 part of it.
So I currently have something like that:
string[] filenames_partial_distinct = Array.ConvertAll(
filenames,
file => System.IO.Path.GetFileNameWithoutExtension(file)
.Split({"_","."}, StringSplitOptions.RemoveEmptyEntries)[1]
)
.Distinct()
.ToArray();
Now, I'm getting filenames that are of form of aaa_bbb_ab12345.txt. So, instead of referring to the second part of the filename, I need to refer to the second to the last.
So, how do I refer to an arbitrary element based on length of array in one line, if it's a result of Split method? Something along lines of:
Array.ConvertAll(filenames, file=>file.Split(separator)[this.Length-2]).Distinct().ToArray();
In other words, if a string method results in an array of strings, how do I immediately select element based on the length of array:
String.Split()[third from end, fifth from end, etc.];
If you use GetFileNameWithoutExtension there will be no extension and therefore splitting by '_' will do it. Then you can take the last part with .Last().
string[] filenames_partial_distinct = Array.ConvertAll(
filenames,
file => Path.GetFileNameWithoutExtension(file).Split('_').Last()
)
.Distinct()
.ToArray();
With the input
string[] filenames = { "aaa_ab12345.txt", "bbb_ab12345.txt",
"aaa_ac12345.txt", "bbb_ac12345", "aaa_bbb_ab12345.txt" };
You get the result
{ "ab12345", "ac12345" }
The StringSplitOptions.RemoveEmptyEntries is only required if there are filenames ending with _ (before the extension).
Seems you're looking for something like this:
string[] arr = filenames.Select(n => n.Substring(n.IndexOf("_") + 1, 7)).Distinct().ToArray();
I usually defer problems like this to regex. They are very powerful. This approach also gives you the opportunity to detect unexpected cases and handle them appropriately.
Here is a crude example, assuming I understood your requirements:
using System;
using System.Linq;
using System.Text.RegularExpressions;
public class Program
{
public static void Main()
{
string MyMatcher(string filename)
{
// this pattern may need work depending on what you need - it says
// extract that pattern between the "()" which is 2 characters and
// 4 digits, exactly; and can be found in `Groups[1]`.
Regex r = new Regex(#".*_(\w{2}\d{4}).*", RegexOptions.IgnoreCase);
Match m = r.Match(filename);
return m.Success
? m.Groups[1].ToString()
: null; // what should happen here?
}
string[] filenames =
{
"aaa_ab12345.txt",
"bbb_ab12345.txt",
"aaa_ac12345.txt",
"bbb_ac12345",
"aaa_bbb_ab12345.txt",
"ae12345.txt" // MyMatcher() return null for this - what should you do if this happens?
};
var results = filenames
.Select(MyMatcher)
.Distinct();
foreach (var result in results)
{
Console.WriteLine(result);
}
}
}
Gives:
ab1234
ac1234
This can be refined further, such as pre-compiled regex patterns, encapsulation in a class, etc.
I have a string that looks like this:
var result = "y-9m-10y-9m-11y-0m-02y-0m-03";
I need to make 2 lists:
one for all the y- objects(9,9,0,0)
and another for the m- objects(10,11,02,03).
How can I do this?
I have this older code from before that doesn't care about the y- objects. Now I need to get both sets.
var result = "m-10m-11m-02m-03";
var months = result.Split(new[] { "m-" }, StringSplitOptions.RemoveEmptyEntries);
Quick and dirty solution using regular expressions and LINQ:
var months = Regex.Matches(result, #"m-(\d+)").Cast<Match>().Select(m => int.Parse(m.Groups[1].Value));
var years = Regex.Matches(result, #"y-(\d+)").Cast<Match>().Select(m => int.Parse(m.Groups[1].Value));
Note that this doesn't do any error checking.
Edit: In the question you seem to use the extracted strings without converting them to int. In this case, omit the int.Parse and use m.Groups[1].Value directly.
I am attempting to compare a comma separated string against a decimal variable and find only the amounts less than my variable.
The problem I'm having is my string looks like so:
1usd,5usd,10usd,20usd
I was able to separate the string into a collection by using the comma separator and regex split, but I don't think this is the best approach since I need to check just the value and reconstruct with the us and comma seperation.
A real world example my program will be handling is
decimal changeAvil = 10
notesSet = 1usd,5usd,10usd,20usd
Result should be notesSet = 1usd,5usd
Its not the prettiest code that has ever been written, but is does the job.
I use Linq to select the prefixes of the strings that are numbers, and then compare these to the value of changeAvil.
using System;
using System.Linq;
namespace stack
{
class Program
{
static void Main(string[] args)
{
decimal changeAvil = 10;
var noteSet = "1usd,5usd,10usd,20usd";
var notes = noteSet.Split(',');
var dict =
notes.ToDictionary(
x => int.Parse(new string(x.TakeWhile(c => char.IsNumber(c))
.ToArray())), // key
x => x); // value
var selection = dict.Where(kvp => kvp.Key <= changeAvil)
.Select(kvp => kvp.Value)
.ToList();
foreach (var s in selection) {
Console.WriteLine(s);
}
}
}
}
The solution returns 1usd, 5usd, and 10usd. If your do not want 10usd to be part of the result change kvp.Key <= changeAvil to kvp.Key < changeAvil in the Where clause of the Linq expression.
You can use split command and remove the letters 'usd' and then iterate through the array and compare
decimal changeAvil = 10
notesSet = 1usd,5usd,10usd,20usd
string noteset_new = noteset.Replace('usd',''); //remove usd
string[] noteset_array = noteset_new.split[',']; //split in to array
now you can iterate the above noteset_array and do what every you want to do.
Using replace and split on the string is using two iterations through the strings characters.
A better way to get the array will be to first add a comma to the end of the string and then use split:
notesSet = 1usd,5usd,10usd,20usd
string[] noteset_array = (notesSet + ',').split['usd,']; //split in to array
PHP developer here working with c#.
I'm using a technique to remove a block of text from a large string by exploding the string into an array and then shifting the first element out of the array and turning what remains back into a string.
With PHP (an awesome & easy language) it was just
$array = explode('somestring',$string);
array_shift($array);
$newstring = implode(' ', $array);
and I'm done.
I get so mad at c# for not allowing me to create dynamic arrays and for not offering me default functions that can do the same thing as PHP regarding arrays. Instead of dynamic arrays I have to create lists and predefine key structures etc. But I'm new and I'm sure there are still equally graceful ways to do the same with c#.
Will someone show me a clean way to accomplish this goal with c#?
Rephrase of question: How can I remove the first element from an array using c# code.
Here is how far I've gotten, but RemoveAt throws a error while debugging so I don't believe it works:
//scoop-out feed header information
if (entry_start != "")
{
string[] parts = Regex.Split(this_string, #entry_start);
parts.RemoveAt(0);
this_string = String.Join(" ", parts);
}
I get so mad at c# for not allowing me to create dynamic arrays
You may take a look at the List<T> class. Its RemoveAt might be worth checking.
But for your particular scenario you could simply use LINQ and the Skip extension method (don't forget to add using System.Linq; to your file in order to bring it into scope):
if (entry_start != "")
{
string[] parts = Regex.Split(this_string, #entry_start).Skip(1).ToArray();
this_string = String.Join(" ", parts);
}
C# is not designed to be quick and dirty, nor it particularly specializes in text manipulation. Furthermore, the technique you use for removing some portion of a string from a beginning is crazy imho.
Why don't you just use String.Substring(int start, int length) coupled with String.IndexOf("your delimiter")?
Here is the corresponding C# code:
string input = "a,b,c,d,e";
string[] splitvals = input.Split(',');
string output = String.Join(",", splitvals, 1, splitvals.Length-1);
MessageBox.Show(output);
You can use LINQ for this:
if (entry_start != "")
this_string = String.Join(" ", Regex.Split(this_string, #entry_start).Skip(1).ToArray());
string split = ",";
string str = "asd1,asd2,asd3,asd4,asd5";
string[] ary = str.Split(new string[] { split }, StringSplitOptions.RemoveEmptyEntries);
string newstr = string.Join(split, ary, 1, ary.Count() - 1);
splits at ",". removes the first record. then combines back with ","
As stated above, you can use LINQ. Skip(int) will return an IEnumerable<string> that you can then cast back as array.
string[] myArray = new string[]{"this", "is", "an", "array"};
myArray = myArray.Skip(1).toArray();
You might be more comfortable with generic lists than arrays, which work more like PHP arrays.
List<T>
But if your goal is "to remove a block of text from a large string" then the easier way would be:
string Example = "somestring";
string BlockRemoved = Example.Substring(1);
// BlockRemoved = "omestring"
Edit
I misunderstood the question, thinking you were just removing the first element from the array where the array consisted of the characters that make up the string.
To split a string by a delimiter, look at the String.Split method instead. Some good examples are given here.