I create a dictionary (Dictionary<string, bool> values).
I create the function:
private Dictionary<string, bool> ChangeValues(int line, Dictionary<string, bool> values)
{
for (int i = 0; i < line; i++)
{
}
return values;
}
I want to change bool values according the number of line.
The table below is the result of a dictionary (only show the bool):
line 0 = values["A"][false]
values["B"][false]
values["C"][false]
line 1 = values["A"][false]
values["B"][false]
values["C"][true]
line 2 = values["A"][false]
values["B"][true]
values["C"][false]
line n...
How I can change the bool value according the number of line?
Thanks.
[update]
After some help, the function is done:
private Dictionary<string, bool> ChangeValues(int line, Dictionary<string, bool> values)
{
string[] keys = values.Keys.ToArray();
keys = (from k in keys orderby k descending select k).ToArray();
for (int i = 0; i < line; i++)
{
for (int j = 0, bit = 1; j < values.Count; j++, bit <<= 1)
{
values[keys[j]] = (i & bit) != 0;
}
}
return values;
}
Thanks to PeterDuniho
If I understand the question correctly, all you want is to be able to iterate all possible combinations of the flags stored in your dictionary. In addition, these flags correspond exactly to the bits in your loop variable i.
If so, then you can just use the bits from the loop variable directly to set the flag values in the dictionary. For a general solution, you do need to pass the key names as well, in the correct order according to the bits you want to set.
For example:
private Dictionary<string, bool> ChangeValues(int line, Dictionary<string, bool> values, string[] keys)
{
for (int i = 0; i < line; i++)
{
for (int j = 0, bit = 1; j < keys.Length; j++, bit <<= 1)
{
values[keys[j]] = (i & bit) != 0;
}
// do something with values here
}
return values;
}
Call like this:
var result = ChangeValues(8, values, new [] { "C", "B", "A" });
Note that the above simply modifies the dictionary that was passed in. I infer from the way the question was asked — "I want to change bool values" — that this was your intent. However, if you actually want to return a whole new dictionary object, you can do so:
private Dictionary<string, bool> ChangeValues(int line, string[] keys)
{
Dictionary<string, bool> values = new Dictionary<string, bool>();
for (int i = 0; i < line; i++)
{
for (int j = 0, bit = 1; j < keys.Length; j++, bit <<= 1)
{
values[keys[j]] = (i & bit) != 0;
}
// do something with values here
}
return values;
}
Of course, in that case the values of the original dictionary are of no use, so there's no need to pass it in, so I've left it out of the parameter list for this version of the method.
If in fact you want to return a new dictionary but still need the old one for some reason (e.g. you want to do something with it, like copying values or something, which you failed to mention in your question), then you can combine the two examples above to suit your needs.
Do you mean like this:
static Dictionary<string, bool> ChangeValues(int line, Dictionary<string, bool> values)
{
switch (line)
{
case 0:
values["A"] = false;
values["B"] = false;
values["C"] = false;
break;
case 1:
values["A"] = false;
values["B"] = false;
values["C"] = true;
break;
case 2:
values["A"] = false;
values["B"] = true;
values["C"] = false;
break;
}
return values;
}
Note: You can also have void return type (as in static void ChangeValues) and omit the return values; statement since you always return the same instance anyway, but that depends on whether you want a "fluent syntax" or not.
After comments, try this:
static Dictionary<string, bool> ChangeValues(int line, Dictionary<string, bool> values)
{
var binary = Convert.ToString(line, 2);
var key = 'A';
foreach (var c in binary)
{
values[key.ToString()] = c == '1';
key++;
}
return values;
}
The comment about void is the same as before.
Related
I've been tasked with taking a string and returning a dictionary that has a map of characters to a list of their indices in a given string. The output should show which characters occur where in the given string.
This code passes the test:
public class CharacterIndexDictionary
{
public static Dictionary<string, List<int>> ConcordanceForString(string input)
{
var result = new Dictionary<string, List<int>>();
for (var index = 0; index < input.Length; index++)
{
// Get the character positioned at the current index.
// We could just use input[index] everywhere, but
// this is a little easier to read.
string currentCharacter = input[index].ToString();
// If the dictionary doesn't already have an entry
// for the current character, add one.
if (!result.ContainsKey(currentCharacter))
{
result.Add(currentCharacter, new List<int>());
}
// Add the current index to the list for
// the current character.
result[currentCharacter].Add(index);
}
return result;
}
}
If I wanted to index characters I'd use a Dictionary<char, List<int>> instead of using a string as the key, but this uses string because the test requires it.
This code block is like your code and in a way that you can understand
public Dictionary<string, List<int>> ConcordanceForString(string s)
{
Dictionary<string, List<int>> newDictionary = new Dictionary<string, List<int>>();
List<char> charList = new List<char>();
foreach (var item in s)
{
if (!charList.Any(x => x == item))
{
charList.Add(item);
List<int> itemInds = new List<int>();
for (int i = 0; i< s.Length; i++)
{
if (s[i] == item)
{
itemInds.Add(i);
}
}
newDictionary.Add(item.ToString(), itemInds);
}
}
return newDictionary;
}
I was working on a HackerRank practice problem and ran into a interesting error
when finished. This code works on every case except the ones causing it to fail
(and they are all timeout exceptions)
Practice Problem
The short version of the problem is you are given a leaderboard (int[]) and "alice's" scores (int[]) you have to find what place she got for each score in the leaderboard...View the link above for the whole problem.
My Solution
public static int[] climbingLeaderboard(int[] scores, int[] alice)
{
int[] results = new int[alice.Length]; //The array that stores alice's placements for each score
Dictionary<int, List<int>> scoresDict = new Dictionary<int, List<int>>(); //Key = x place (1st, 2nd, etc), the list is all the numbers that are at x place
for(int i = 0; i < alice.Length; i++)
{
List<int> alicePlace = scores.ToList<int>();
//Add the score to the array (converted to list for .Add)
alicePlace.Add(alice[i]);
//Sorts in reverse order to get the new score in the correct place
alicePlace = RecalculateScores(alicePlace);
//Breaks down the scores into the dictionary above
scoresDict = SeperateScores(alicePlace);
//Addes the place to the array
results[i] = GetPlace(scoresDict, alice[i]);
}
return results;
}
//Returns scores[] in reverse SORTED order
public static List<int> RecalculateScores(List<int> scores)
{
List<int> scoresRet = scores;
scoresRet.Sort();
scoresRet.Reverse();
return scoresRet;
}
//Gets the place (key) for where score is in the dict's value list
public static int GetPlace(Dictionary<int, List<int>> dict, int score)
{
foreach (int i in dict.Keys)
{
foreach (int ii in dict[i])
{
if (ii == score)
{
return i;
}
}
}
return -1;
}
//Seperates the array into a dictionary by score placement
public static Dictionary<int, List<int>> SeperateScores(List<int> scores)
{
int placeholder = scores[0];
int currentPlace = 1;
Dictionary<int, List<int>> scoresByPlace = new Dictionary<int, List<int>>();
for (int i = 0; i < scores.Count(); i++)
{
if (scores[i] == placeholder)
{
if (!scoresByPlace.Keys.Contains(currentPlace) || scoresByPlace[currentPlace] == null)
{
scoresByPlace[currentPlace] = new List<int>();
}
scoresByPlace[currentPlace].Add(scores[i]);
placeholder = scores[i];
}
else
{
currentPlace++;
if (!scoresByPlace.Keys.Contains(currentPlace) || scoresByPlace[currentPlace] == null)
{
scoresByPlace[currentPlace] = new List<int>();
}
scoresByPlace[currentPlace].Add(scores[i]);
placeholder = scores[i];
}
}
return scoresByPlace;
}
Error
Whenever it gets tested with a large array amount (2 Million for examples) it returns an timeout exception (probably HackerRank generated to make it harder)
Attempted solution
Believe it or not but I changed a lot of things on the above code. For one,the results array in the first function used to be a list but I changed to array to make it faster. I feel the dictionary/List is slowing everything down but I need them for the solution (Especially the dictionary). Any Help would be appreciated
I have dictionary of int (Dictionary<int, int>) which has index of all parenthesis in a string (key was openStartParenthesisIndex and value was closeEndParenthesisIndex)
e.g in text
stringX.stringY(())() -> stringX.stringY$($()^)^$()^
$ = openParenthesisStartIndex
^ = closeParenthesisEndIndex
Dictionary items:
key value
(openParenthesisStartIndex) --- (closeParenthesisEndIndex)
item1 15 19
item2 16 18
item3 19 21
My problem was when I loop my dictionary and try to remove it on string, next loop the index was not valid since its already change because I remove it .
string myText = "stringX.stringY(())()";
Dictionary<int, int> myIndexs = new Dictionary<int, int>();
foreach (var x in myIndexs)
{
myText = myText.Remove(item.Key, 1).Remove(item.Value-1);
}
Question: how can i remove all index in a string (from startIndex[key] to endIndex[value])?
To prevent the index from changing, one trick is to remove the occurences starting from the end:
string myText = stringX.stringY(())();
Dictionary<int, int> myIndexs = new Dictionary<int, int>();
var allIndexes = myIndexs.Keys.Concat(myIndexs.Values);
foreach (var index in allIndexes.OrderByDescending(i => i))
{
myText = myText.Remove(index, 1);
}
Note that you probably don't need a dictionary at all. Consider replacing it by a list.
StringBuilder will be more suited to your case as you are continuously changing data. StringBuilder MSDN
Ordering the keys by descending order will work as well for removing all indexes.
Another workaround could be to place an intermediary character at required index and replace all instances of that character in the end.
StringBuilder ab = new StringBuilder("ab(cd)");
ab.Remove(2, 1);
ab.Insert(2, "`");
ab.Remove(5, 1);
ab.Insert(5, "`");
ab.Replace("`", "");
System.Console.Write(ab);
Strings when you make a change to a string a new string is always created, so what you want is to create a new string without the removed parts. This code is a little bit complicated because of how it deals with the potential overlap. Maybe the better way would be to cleanup the indexes, making a list of indexes that represent the same removals in the right order without overlap.
public static string removeAtIndexes(string source)
{
var indexes = new Tuple<int, int>[]
{
new Tuple<int, int>(15, 19),
new Tuple<int, int>(16, 18),
new Tuple<int, int>(19, 21)
};
var sb = new StringBuilder();
var last = 0;
bool copying = true;
for (var i = 0; i < source.Length; i++)
{
var end = false;
foreach (var index in indexes)
{
if (copying)
{
if (index.Item1 <= i)
{
copying = false;
break;
}
}
else
{
if (index.Item2 < i)
{
end = true;
}
}
}
if (false == copying && end)
{
copying = true;
}
if(copying)
{
sb.Append(source[i]);
}
}
return sb.ToString();
}
I want to provider user with option to set ToolStripMenuItem.ShortcutKeys via configuration file, so I've figured out that I need somehow transform string to Keys.
I've already found how to do that for simple values using Enum.Parse, but it won't recognize formats like:
Ctrl+i (with space at the end)
i
Ctrl+Alt+Esc
Q: Is there any standardized way of parsing stings (Ctrl+i) to Keys?
I'd like to avoid writing my own function that will split text into pieces and then handle each case/special string separately.
The string you see in the Properties window for the ShortcutKeys property is generated by a TypeConverter. You can use that type converter in your own code as well. Like this:
var txt = "Ctrl+I";
var cvt = new KeysConverter();
var key = (Keys)cvt.ConvertFrom(txt);
System.Diagnostics.Debug.Assert(key == (Keys.Control | Keys.I));
Do beware that I or Ctrl+Alt+Escape are not valid short-cut keys. KeysConverter will not complain, you'll get the exception when you assign the ShortCutKeys property. Wrap both with try/except to catch invalid config data.
Yes, you can separate the values with a , - however your string would still need massaged because Ctrl and Esc are not valid Keys values. They still need to be valid values. So consider the following code:
var keys = "Ctrl+Alt+Esc";
keys = keys.Replace("+", ",").Replace("Ctrl", "Control").Replace("Esc", "Escape");
var k = (Keys)Enum.Parse(typeof(Keys), keys);
Further, here is the code in the Enum class that's going to pick that up:
string[] array = value.Split(Enum.enumSeperatorCharArray);
ulong[] array2;
string[] array3;
Enum.GetCachedValuesAndNames(runtimeType, out array2, out array3, true, true);
for (int i = 0; i < array.Length; i++)
{
array[i] = array[i].Trim();
bool flag = false;
int j = 0;
while (j < array3.Length)
{
if (ignoreCase)
{
if (string.Compare(array3[j], array[i], StringComparison.OrdinalIgnoreCase) == 0)
{
goto IL_152;
}
}
else
{
if (array3[j].Equals(array[i]))
{
goto IL_152;
}
}
j++;
continue;
IL_152:
ulong num2 = array2[j];
num |= num2;
flag = true;
break;
}
if (!flag)
{
parseResult.SetFailure(Enum.ParseFailureKind.ArgumentWithParameter, "Arg_EnumValueNotFound", value);
return false;
}
}
The value of enumSeperatorCharArray is:
private static readonly char[] enumSeperatorCharArray = new char[]
{
','
};
I am looking for a better way to update values in my List/Array:
My code is like -
String[] values = baseValue.Split(new []{'+'});
Because the 'values' can have decimal/string values - I want to update items in this list to remove any value after decimal -
for (int i = 0; i < values.Count(); i++)
{
decimal newvalue;
if (Decimal.TryParse(values[i], out newvalue))
{
values[i] = Decimal.ToInt32(newvalue).ToString();
}
}
Is there a better way to achieve above using Linq/without Linq ?
You could use string operations, instead of converting to decimal then to int and finally back to string.
string[] values = baseValue.Split('+');
for (int i = 0; i < values.Length; i++)
{
int pos = values[i].IndexOf('.');
if (pos >= 0) {
values[i] = values[i].Substring(0, pos);
}
}
Of cause no rounding occurs here.
String.Split has an overload with one argument params char[] separator. Because of the params keyword, you can specify as many characters as you want, without having to create an array explicitly.
string[] result = s.Split('x', 'y', 'z');
Use values.Length which is a property built into array types. values.Count() is a LINQ extension method, which enumerates all the array items and is therefore not efficient.
You could use an extension method:
public static void ConvertDecimalToInts(this string[] values)
{
for (int i = 0; i < values.Count(); i++)
{
decimal newvalue;
if (Decimal.TryParse(values[i], out newvalue))
{
values[i] = Decimal.ToInt32(newvalue).ToString();
}
}
}
And use it as so:
String[] values = baseValue.Split(new[] { '+' });
values.ConvertDecimalToInts();
Olivier's answer is probably better in that it doesn't require three conversions, but you can do this with Linq if you wish:
values = baseValue.Split('+')
.Select(v => Decimal.ToInt32(Decimal.Parse(v)).ToString());