As everyone would be aware the typical way to use the Format method is
string res = string.format("<Field Name='Title'>{0}</Field>", "SomeValue");
Where {0} will become SomeValue
And for each subsequent parameter you simply increment the number so the next one might look like this
string res = string.format("<Field Name='Title'>{0}</Field><Field Name='FirstName'>{1}</Field>", "SomeValue", "SomeValue1");
The problem I am having is that any time I make a change to the parameters in the xml I am trying to build I need to go through and reorder the format string values ie: {1} becomes {2}, {2} becomes {3} and so forth.
What I am wondering is if there is some way where I can omit the integer value from the placeholder and the format function might be able to work out the order based on the index of the parameters passed in?
I am not sure about a method, but you could use some sort of regex and have it replace based off of named strings instead of indexes, however that is not as pretty.
Another solution would be to just fill your parameters differently. For example, if the 0 spot is changing, then instead of renumbering, just add your new parameter at the beginning of the parameters list instead of just adding it to the end. This will still require a re-write of the code, though.
Lastly, why are you manually formatting the XML, when you can use XMLDocuments and XMLWriters? That will allow you to enter these values in a more controlled way, possibly (I cannot say for sure without seeing the code around it)
var fields = new Dictionary<string, string>
{
{"Title", "someTitle"},
{"FirstName", "Johnny"},
{"LastName", "Depp"}
};
var res = string.Join("", fields.Select(kvp => string.Format("<Field Name='{0}'>{1}</Field>",
kvp.Key,
kvp.Value)));
Use a refactoring tool such as Resharper. It will do the reformatting in String.Format for you. There is no inherent way to do what you ask.
Resharper will allow you to insert elements in arbitrary places and reorder the indices. It will allow you remove as well.
Alternatively, you could use StringTemplate
Related
I have a string with the format 00-00 and I want to increment it to 00-01.
Currently I am using Split() but I have the feeling that my approach is not really best practice.
I don't have to worry about edge cases and just want to know if there is an elegant solution.
Thanks
Linq approach without edge cases like 00-99 or 99-99
string input ="07-01";
string result = string.Join("-", input.Split('-')
.Select(int.Parse)
.Select((x, i) => (i == 1 ? ++x : x).ToString("00")));
Your method of utilizing string.Split() would be my suggestion too.
However, I'm wondering if you are repeatedly incrementing that number. if this is a one time action, then I agree with using the split method.
If you are continually incrementing this number (e.g. as a counter), you will start noticing that it takes more resources to do string operations (split) and conversions (string to int, int to string); compared to incrementing the value of the integer.
In this case, I would advocate that you keep the integer value in memory, and keep using that to generate your output string, instead of always having to start from scratch.
However, the latter suggestion only applies if you keep incrementing the same values. Your question did not specify that that is the case.
I'm currently using an in-memory cache and looking to switch to a distributed caching mechanism with Redis. I had a look at ServiceStack's client, but the rate-limiting licensing doesn't work for me, so Booksleeve seems to be recommended.
I've set up a test program to just set and that get that same value back from Booksleeve, but it seems like the result I'm getting back isn't in my expected format, and I'm not sure what the right way to handle this is (there isn't much in the way of documentation that I can see). Here is my simple test program:
RedisConnection conn = new RedisConnection("localhost", 6379);
conn.Open();
conn.Strings.Set(1, "test", 100);
var task = conn.Strings.Get(1, "test");
task.Wait();
var x = task.Result; // byte[] result = {49, 48, 48};
var str = BitConverter.ToString(x); // string result = "31-30-30";
var l = BitConverter.ToInt64(x, 0); // Destination array is not long enough to copy all the items in the collection. Check array index and length.
As you can see, at no point do I get back the same value of "100" that I cached with my original "Set" statement. It's also interesting that I don't seem to be able to cache by numeric values (since Get and Set are members of conn.Strings). Is the recommended approach to just .ToString() all numeric key values?
Any explanation as to why I'm unable to get back the original cached value (and best practices for doing this) would be greatly appreciated.
My answer has two parts:
Redis always saves strings, even if you set a number. BUT it internally knows to do some specific actions on strings that represent numbers.
For example, if right after your first .Set() assignment you'll add:
conn.Strings.Increment(1, "test", 1);
the test key will have the value "101", which is a string, but one that is made out of an arithmetic calculation by Redis.
You need to fix your conversion function. Instead of using BitConverter, that's the right way to convert:
var str = System.Text.Encoding.UTF8.GetString(x);
var value = int.Parse(str);
Of course, this snippet doesn't include any kind of error checking, which is fairly easy to apply (e.g. what if the value is empty or contains something that is not a number).
As for your last question, is using .ToString() the recommended approach - yes. That's the way to work with Redis. But of course, you can make your own utility wrappers that take care of converting values that suppose to contian numbers, to numbers. Something like GetIntValue(string key) or so.
I want to know which is the most efficient way to store a set of list of strings in C#.
Background
My goal is to store information about "properties" like Hold(object) or Location(x,y,object). To do this I have a dictionary that map the property name to a "set of values".
For example, suppose I have a "location" set for the "location" property with these values
location -> ["1","2","robot1"]
["2","3","robot2"]
["2","5","key1"]
I want to perform query like
DB["location"].Contains(["1","2","robot1"])
I don't know if it is possible but it is to give you an idea of what I need. :)
What I have done
I have to modify and access these data frequently so I opted for an HashSet. But I have two main options:
The first is to use something like HashSet<string[]>. The problem is I think that HashSet cannot find duplicates because the standard behavior is to compare arrays by reference. For the same reason I don't know a good way to solve the "check if a [a,b,c] is contained in the set" problem.
The second is to use something like HashSet<List<string>>. But I don't need a List to store a simple set of tuple. It seems to me too much for a simple job like that.
An alternative is to write my own class to store "arguments" but I don't want to do this if something exists in the standard library. :)
Thanks :)
An alternative is to write my own class to store "arguments" but I don't want to do this if something exists in the standard library. :)
This would actually be my preference. While it's a bit of work to write this up, having an actual type to hold the values provides the ability to build the equality directly into the type, and makes its usage very explicit.
In your case, you could store 2 ints and a string instead of 3 strings, etc. More importantly, the int and string values can be named appropriately, which in turn makes your code far more readable and understandable.
Use HashSet and Tuple might be a choice
HashSet<Tuple<int, int, string>> collections;
and if you prefer using all strings:
HashSet<Tuple<string, string, string>> collections;
And for equality of Tuple, you might find this MSDN link useful. No matter which form you like, you can use below example as a reference:
Tuple<string, double, int>[] scores =
{ Tuple.Create("Ed", 78.8, 8),
Tuple.Create("Abbey", 92.1, 9),
Tuple.Create("Ed", 71.2, 9),
Tuple.Create("Sam", 91.7, 8),
Tuple.Create("Ed", 71.2, 5),
Tuple.Create("Penelope", 82.9, 8),
Tuple.Create("Ed", 71.2, 9),
Tuple.Create("Judith", 84.3, 9) };
// Test each tuple object for equality with every other tuple.
for (int ctr = 0; ctr < scores.Length; ctr++)
{
var currentTuple = scores[ctr];
for (int ctr2 = ctr + 1; ctr2 < scores.Length; ctr2++)
Console.WriteLine("{0} = {1}: {2}", currentTuple, scores[ctr2],
currentTuple.Equals(scores[ctr2]));
Console.WriteLine();
}
}
I have these below strings to sort (String Format: 121030-1833 --> YYDDMM-HHMM)
String Example:
121030-1833
120823-2034
120807-2014
120627-2316
120525-1136
111226-1844
I want to sort them from latest to old format.
Which sort method will be the best to use here?
Updated problem statement
dictionary[String,string] "dictLocation" values with me, Want to sort the Dictionary according to its key (Key-YYMMDD-HHMM, latest to oldest)
{[110901-1226, sandyslocation.110901-1226]}
{[120823-2034, andyslocatio.120823-2034]}
{[110915-1720, mylocation.110915-1720]}
{[121030-1833, mylocation.121030-1833]}
I am trying this var latestToOldest = dictLocation.OrderBy(key => key.Key)
It not giving me proper result, Is there anything i am missing ?
As it happens, just sorting them in a descending way will work:
var latestToOldest = original.OrderByDescending(x => x);
That's assuming you want to assume all values are within the same century. (If you can possibly change the format, I'd suggest using a 4-digit year for clarity.)
However, I would recommend parsing the values into DateTime values as early as possible. Whenever you can, keep your data in its most "natural" form. Fundamentally these are dates and times, not strings - so convert them into that format early, and keep them in that format as long as you possibly can.
var sortedDateStrings = dateStrings.Sort().Reverse();
// or
var sortedDateStrings = dateStrings.OrderByDescending(x => x);
I have a Dictionary the first string, the key's, must never change.. it cant be deleted or anything.. but the value, i keep adding lines, and lines, and lines to the values.. i just create new lines with \r\n or \r .. and im just wondering what would be the easiest way to retain just the last 50 lines. and delete anything over the 50 lines.. im doing this because when i return it i have to put the values through a char array, and go through each letter, and this can be slow if there is too much data. any suggestions?
Guffa's general idea is right - your data structure should reflect what you actually want, which is a list of strings rather than a single string. The concept of "the last 50 lines" is pretty obviously to do with a collection rather than a single string, even if you've originally read it that way.
However, I'd suggest using a LinkedList<T> rather than a List<T>: every time you remove the first element of a List<T>, everything else has to shuffle up. List<T> is great for giving random access and not too bad at adding to the end, but sucks for removing from the start. LinkedList<T> is great at giving you iterator access, adding to / removing from the start, and adding to / removing from the end. It's a better fit. (If you really wanted to go to town you could even write your own fixed-size circular buffer type which encapsulated the logic for you; this would give the best of both worlds, in the situation where you don't want to be able to expand beyond a certain size.)
Regarding your comments to Guffa's answer: it's pretty common to convert input into a form which is more appropriate for processing, then convert it back to the original format for output. The reason why you do it is precisely the "more appropriate" bit. You don't want to have to parse the string for line breaks as part of the "updating the dictionary" action, IMO. In particular, it sounds like you're currently introducing the idea of "lines" where the original text is just being read in as strings. You're effectively creating your own "collection" class backed by a string, by delimiting strings with line breaks. That's inefficient, error-prone, and much harder to manage than using the built-in collections. It's easy to perform the conversion to a line-break-delimited string at the end if you want it, but it sounds like you're doing it way too early.
Instead of concatenating the lines, use a Dictionary<string, List<string>>. When you are about to add a string to the list you can check the count and remove the first string if the list already has 50 strings:
List<string> list;
if (!theDictionary.TryGetValue(key, out list)) {
theDictionary.Add(list = new List<string>());
}
if (list.Count == 50) {
list.RemoveAt(0);
}
list.Add(line);