Okay So I have this Hashset that contains 3 items and I want to apply some logic on it such that I am able to append some predefined 3 values for the each item present inside the hashset
for example,
HashSet<string> hs = new HashSet<string>(); //it could be string or some other class object
hs.add("Red");
hs.add("Yellow");
hs.add("Blue");
//Some predefined values for those strings that I want to append to them
string[] str = {Alpha, Beta, Gamma}
The output I desire is:
unique strings associating "RedAlpha", "YellowBeta", "bluegamma"
for example s1 = "RedAlpha", s2 = "YellowBeta", s3 = "bluegamma";
I then want to apply some different logic to each of them later but then I guess that is a different thing
My Tried code
int count = 1;
int index = 0;
string s = "";
foreach(string strr in hs)
{
string s + count = strr + str[index]; // I don't know how to make new unique string
count++;
index++;
}
My other Tried Code,
foreach(string strr in hs)
{
string s = strr + str[index];
s = s + ","
index++;
}
s.split(",");
When you want to merge 2 collection together and perform some operation on them, use the Zip method. See this answer for an explanation of Zip method.
Here is how to achieve what you need:
HashSet<string> hs = new HashSet<string>();
hs.Add("Red");
hs.Add("Yellow");
hs.Add("Blue");
string[] str = { "Alpha", "Beta", "Gamma" };
List<KeyValuePair<string, string>> kvps =
hs.Zip(str, (left, right) => new KeyValuePair<string, string>(left, right))
.ToList();
If you want a dictionary, it is straight forward as well:
Dictionary<string, string> kvps =
hs.Zip(str, (left, right) => new { left, right })
.ToDictionary(x => x.left, x.right);
Put them in a list:
int index = 0;
var list = new List<string>();
foreach(string strr in hs)
{
list.Add(strr + str[index]);
index++;
}
Console.WriteLine(list[0]); //RedAlpha
Related
I have a text file that I am reading to pull out register values and what they contain.
2 lines from the array pulled out is: (full list is about 700)
0x0003 = 0x0069
0x0007 = 0x0078
I would like to split these into two arrays or one 2-dimensional array, whatever is best(I am new to using arrays)
My goal is to search the array for example for register 3, find the index then extract the information from the 2nd arrays corresponding index.
Here is my code so far ,
List<string> registerFullList1 = new List<string>();
for (int i = 0; i < 2000; i++)
{
string[] importStringArray1 = new string[2000];
importStringArray1[i] = importStringArray1[i] + objReader.ReadLine() + "\r\n";
//code to extract register info from string array
string listsplit1 = Regex.Match(importStringArray1[i], #"(?<= 0x)[0-9A-Fa-z\s\=]{13}").Value;
if (listsplit1.Contains("0x")) //code to add to list only registers and ignore empty lines
{
registerFullList1.Add(Convert.ToString(listsplit1));
}
}
int[] index = new int[2000]; // is there a way here that I don't have to assign 0,1,2,3 to each assignment?
index[0] = registerFullList1.FindIndex(x => x.StartsWith("0003 ="));
Register3.Text = Regex.Match(registerFullList1[index[0]], #"(?<= 0x)[0-9A-F]{4}").Value;
index[1] = registerFullList1.FindIndex(x => x.StartsWith("0007 ="));
Register7.Text = Regex.Match(registerFullList1[index[1]], #"(?<= 0x)[0-9A-F]{4}").Value;
This all works no problem and I am displaying the register content in text boxes. But I would like two arrays so it is more proper, one with register numbers and one with content. I cant figure it out, any help would be appreciated.
UPDATE
final code after reading answers,
List<string> registerNumberList = new List<string>();
List<string> registerContentList = new List<string>();
List<string> registerFullList = new List<string>();
for (int i = 0; i < 2000; i++)
{
string[] importStringArray1 = new string[2000];
importStringArray1[i] = importStringArray1[i] + objReader.ReadLine() + "\r\n";
string listsplit1 = Regex.Match(importStringArray1[i], #"(?<= 0x)[0-9A-Fa-z\s\=]{13}").Value; // #"(?<== 0x)[0-9A-F]{4}"
string listsplit2 = Regex.Match(importStringArray1[i], #"(?<= 0x)[0-9A-Fa-z\s\=]{4}").Value;// pulls out the register number from original array
string listsplit3= Regex.Match(importStringArray1[i], #"(?<== 0x)[0-9A-Fa-z\s\=]{4}").Value;//pulls out register content from original array
if (listsplit1.Contains("0x"))
{
registerNumberList.Add(Convert.ToString(listsplit3));//makes a list with register numbers
registerContentList.Add(Convert.ToString(listsplit2) );//makes a list with register content
registerFullList.Add(Convert.ToString(listsplit2) + "=" + Convert.ToString(listsplit3));//the full list
}
}
Dictionary <string, string> registers = registerFullList.Select(line => line.Split('=')
.ToArray())
.ToDictionary(items => items[0], items => items[1]); //joins the register numbers and content into a dictionary with just 4 decimal values for each
list1.Text = String.Join("\r\n", registerFullList);
list2.Text = registers["0010"]; // pulls out register info
Thanks guys
I suggest using Linq:
If you insist on the array:
int[][] result = File
.ReadLines(#"C:\myFile.txt")
.Select(line => line
.Split('=')
.Select(item => Convert.ToInt32(item, 16))
.ToArray())
.ToArray();
In case first index is unique one (and thus can serve as a key) you can materialize the data as a dictionary:
Dictionary<int, int> result = File
.ReadLines(#"C:\myFile.txt")
.Select(line => line
.Split('=')
.Select(item => Convert.ToInt32(item, 16))
.ToArray())
.ToDictionary(items => items[0], items => items[1]);
...
// value == 0x0078 (120)
int value = result[0x0007];
Try using a dictionary :
Dictionary<string, string> registersKeyValue = new Dictionary<string, string>();
string content = registersKeyValue
.Where(keyValuePair => keyValuePair.Key == "0x0003")
.FirstOrDefault()
.Value;
This is the code using LINQ, it stores the values into list
string StringRegex = "\"(?:[^\"\\\\]|\\\\.)*\"";
Dictionary<string, string> dictionaryofString = new Dictionary<string, string>()
{
{"String", StringRegex}
};
var matches = dictionaryofString.SelectMany(a => Regex.Matches(input,a.Value)
.Cast<Match>()
.Select(b =>
new
{
Index = b.Index,
Value = b.Value,
Token = a.Key
}))
.OrderBy(a => a.Index).ToList();
for (int i = 0; i < matches.Count; i++)
{
if (i + 1 < matches.Count)
{
int firstEndPos = (matches[i].Index + matches[i].Value.Length);
if (firstEndPos > matches[(i + 1)].Index)
{
matches.RemoveAt(i + 1);
i--;
}
}
}
foreach (var match in matches)
{
Console.WriteLine(match);
}
Can it not be stored into Array? Where I can display only item I want. Just like here the output is {Index=, Value=, Token=}
Meanwhile I want the output that be of just "Value" "Token" index not needed.
You can use ToArray instead. But List gives you the desired array functionality already, you can access an item by its index.
var exampleQuery = select c from componentsDemo;
var list = exampleQuery.ToList();
var secondElement = list[1]; // <- demo only, there could be an exception thrown, if there's less than two elements in the list
EDIT: as I can see from your comments, you need this:
foreach (var match in matches)
{
Console.WriteLine(match.Value + ", " + match.Token);
}
I have an array for example("1:2","5:90","7:12",1:70,"29:60") Wherein ID and Qty are separated by a ':' (colon), what I want to do is when there's a duplicate of IDs the program will add the qty and return the new set of arrays so in the example it will become ("1:72","5:90","7:12","29:60").
Ex.2 ("1:2","5:90","7:12","1:70","29:60","1:5") becomes ("1:77","5:90","7:12","29:60").
I want to solve it without using linq.
var foo = array.Select(s => s.Split(':'))
.GroupBy(x => x[0])
.Select(g =>
String.Format(
"{0}:{1}",
g.Key,
g.Sum(x => Int32.Parse(x[1]))
)
)
.ToArray();
Note, it's not necessary to parse the "keys," only the values.
Without LINQ:
var dictionary = new Dictionary<string, int>();
foreach (var group in array) {
var fields = group.Split(':');
if (!dictionary.ContainsKey(fields[0])) {
dictionary.Add(fields[0], 0);
}
dictionary[fields[0]] += Int32.Parse(fields[1]);
}
string[] foo = new string[dictionary.Count];
int index = 0;
foreach (var kvp in dictionary) {
foo[index++] = String.Format("{0}:{1}", kvp.Key, kvp.Value);
}
You have to do this manually. Loop through each list, check the ID for each element. Put it in a Dictionary<int, int>, Dictionary<id, qt>. If the dictionary contains the id, add it to the value.
Loop, add, check using Dictionary class.
If you want it without LINQ...
var totalQuantities = new Dictionary<int, int>();
foreach(var raw in sourceArr) {
var splitted = raw.Split(':');
int id = int.Parse(splitted[0]);
int qty = int.Parse(splitted[1]);
if(!totalQuantities.ContainsKey(id)) {
totalQuantities[id] = 0;
}
totalQuantities[id] += qty;
}
var result = new string[totalQuantities.Count];
int i=0;
foreach(var kvp in totalQuantities) {
result[i] = string.Format("{0}:{1}", kvp.Key, kvp.Value);
i++;
}
(
from raw in arr
let splitted = raw.Split(':')
let id = int.Parse(splitted[0])
let qty = int.Parse(splitted[1])
let data = new { id, qty }
group data by data.id into grp
let totalQty = grp.Sum(val => val.qty)
let newStr = string.Format("{0}:{1}", grp.Key, totalQty
select newStr
)
.ToArray()
Note that the code may contain accidental errors, as it was written in notepad.
var input=new string[]{"1:2","5:90","7:12","1:70","29:60","1:5"};
var result=input
.Select(s=>s.Split(':'))
.Select(x=>x.Select(s=>int.Parse(s)).ToArray())
.GroupBy(x=>x[0])
.Select(g=>g.Key+":"+g.Sum(x=>x[1]));
I was too lazy to specify the culture everywhere. You probably want to do that before putting it into production, or it will fail for cultures with unusual integer representations.
var totals=new Dictionary<int,int>
foreach(string s in input)
{
string[] parts=s.Split(':');
int id=int.Parse(parts[0]);
int quantity=int.Parse(parts[0]);
int totalQuantity;
if(!totals.TryGetValue(id,out totalQuantity))
totalQuantity=0;//Yes I know this is redundant
totalQuanity+=quantity;
totals[id]=totalQuantity;
}
var result=new List<string>();
foreach(var pair in totals)
{
result.Add(pair.Key+":"+pair.Value);
}
try this:
List<string> items = new List<string>(new string[] { "1:2", "5:90", "7:12", "1:70", "29:60" });
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (string item in items)
{
string[] data = item.Split(':');
string key = data[0];
if (!dictionary.ContainsKey(data[0]))
{
int value = dictionary[data[0]];
dictionary[key] += int.Parse(data[1]);
}
}
//Used dictionary values here
I have a Dictionary<string, int> and I am reading some strings from a list... I want to add them in the dictionary, but if the string is already in the dictionary, I want its value to increase by 1.
The code I tried is as below, but there are some strings that are increased with every input.. Is something wrong?
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach (String recordline in tags)
{
String recordstag = recordline.Split('\t')[1];
String tagToDic = recordstag.Substring(0, (recordstag.Length-1) );
if (dictionary.ContainsKey(tagToDic) == false)
{
dictionary.Add(tagToDic, 1);
}
else
{
try
{
dictionary[tagToDic] = dictionary[tagToDic] + 1;
}
catch (KeyNotFoundException ex)
{
System.Console.WriteLine("X" + tagToDic + "X");
dictionary.Add(tagToDic, 1);
}
}
}
EDIT: To answer your comments... I am removing the last char of the string because it is always a blank space...
My input is like:
10000301 business 0 0,000
10000301 management & auxiliary services 0 0,000
10000316 demographie 0 0,000
10000316 histoire de france 0 0,000
10000347 economics 0 0,000
10000347 philosophy 1 0,500
and i want only the string like "business" or "management & auxiliary services" etc.
You are splitting each string in the input string array and selecting the 2nd string in the string array. Then you are removing the last character of this 2nd string using SubString. Hence all strings that differ only in the last character would be considered the same and incremented. Thats why you might be seeing "some strings that are increased with every input".
EDIT: If the purpose of removing the last char is to remove space, Use String.Trim instead.
Another edit is using TryGetValue instead of ContainsKey which performs better to increment your value. Code has been edited below.
Try this:
Dictionary<string, int> dictionary = new Dictionary<string, int>();
foreach(string recordline in tags)
{
string recordstag = recordline.Split('\t')[1].Trim();
int value;
if (!dictionary.TryGetValue(recordstag, out value))
dictionary.Add(recordstag, 1);
else
dictionary[recordstag] = value + 1;
}
No need for a dictionary, can be solved using this Linq query.
(Assuming you want the complete string after \t)
var q =
from s in tags.Select (t => t.Substring(t.IndexOf("\t")))
group s by s into g
select new
{
g.Key,
Count = g.Count()
};
And if you need it as a dictionary just add:
var dic = q.ToDictionary (x => x.Key, x => x.Count);
Your input string first split and then substring of it returned to tagToDic, So maybe n strings have a same tagToDic.
Extension method
public static void Increment(this Dictionary<string, int> dictionary, string key)
{
int val;
dictionary.TryGetValue(key, out val);
if (val != null)
dictionary[key] = val + 1;
}
Dictionary<string, int> dictionary = new Dictionary<string, int>();
// fill with some data
dictionary.Increment("someKey");
It's probably easier just to re-add the dictionary value after you retrieve the count from the existing one.
Here's some psuedo code to handle the look up logic.
Dictionary<string, int> _dictionary = new Dictionary<string, int>();
private void AdjustWordCount(string word)
{
int count;
bool success = _dictionary.TryGetValue(word, out count);
if (success)
{
//Remove it
_dictionary.Remove(word);
//Add it back in plus 1
_dictionary.Add(word, count + 1);
}
else //could not get, add it with a count of 1
{
_dictionary.Add(word, 1);
}
}
How about:
Dictionary<string, int> dictionary = new Dictionary<string, int>();
string delimitedTags = "some tab delimited string";
List<string> tags = delimitedTags.Split(new char[] {'\t'}, StringSplitOptions.None).ToList();
foreach (string tag in tags.Distinct())
{
dictionary.Add(tag, tags.Where(t => t == tag).Count());
}
If you have them in a list you could just group them and make your list.
list.GroupBy(recordline => recordline.Split('\t').Substring(0, (recordstag.Length-1),
(key, ienum) => new {word = key, count = ienum.Count()});
Then you can put that in a dictionary or iterate it or something.
Your dictionary code looks like it will function the way you expect.
My best guess is that your string-splitting code is not working correctly.
You'd have to give us some sample inputs to verify this though.
Anyway, your entire block of code could be simplified and rewritten with LINQ as:
var dictionary = tags
.Select(t => {
var recordstag = t.Split('\t')[1];
return recordstag.Substring(0, recordstag.Length-1);
})
.GroupBy(t => t)
.ToDictionary(k => k.Key, v => v.Count())
;
I'm looking to combine the contents of two string arrays, into a new list that has the contents of both joined together.
string[] days = { "Mon", "Tue", "Wed" };
string[] months = { "Jan", "Feb", "Mar" };
// I want the output to be a list with the contents
// "Mon Jan", "Mon Feb", "Mon Mar", "Tue Jan", "Tue Feb" etc...
How can I do it ? For when it's only two arrays, the following works and is easy enough:
List<string> CombineWords(string[] wordsOne, string[] wordsTwo)
{
var combinedWords = new List<string>();
foreach (var wordOne in wordsOne)
{
foreach (string wordTwo in wordsTwo)
{
combinedWords.Add(wordOne + " " + wordTwo);
}
}
return combinedWords;
}
But I'd like to be able to pass varying numbers of arrays in (i.e. to have a method with the signature below) and have it still work.
List<string> CombineWords(params string[][] arraysOfWords)
{
// what needs to go here ?
}
Or some other solution would be great. If it's possible to do this simply with Linq, even better!
What you want to do is actually a cartesian product of all the arrays of words, then join the words with spaces. Eric Lippert has a simple implementation of a Linq cartesian product here. You can use it to implement CombineWords:
List<string> CombineWords(params string[][] arraysOfWords)
{
return CartesianProduct(arraysOfWords)
.Select(x => string.Join(" ", x))
.ToList();
}
To cross join on any amount of arrays of strings:
// Define other methods and classes here
List<string> CombineWords(params string[][] arraysOfWords)
{
if (arraysOfWords.Length == 0)
return new List<string>();
IEnumerable<string> result = arraysOfWords[0];
foreach( string[] words in arraysOfWords.Skip(1) )
{
var tempWords = words;
result = from r in result
from w in tempWords
select string.Concat(r, " ", w);
}
return result.ToList();
}
Code below works for any number of arrays (and uses linq to some degree):
List<string> CombineWords(params string[][] wordsToCombine)
{
if (wordsToCombine.Length == 0)
return new List<string>();
IEnumerable<string> combinedWords = wordsToCombine[0].ToList();
for (int i = 1; i < wordsToCombine.Length; ++i)
{
var temp = i;
combinedWords = (from x in combinedWords from y in wordsToCombine[temp]
select x + " " + y);
}
return combinedWords.ToList();
}
public static List<string> CombineWords(params string[][] arraysOfWords)
{
var strings = new List<string>();
if (arraysOfWords.Length == 0)
{
return strings;
}
Action<string, int> combineWordsInternal = null;
combineWordsInternal = (baseString, index) =>
{
foreach (var str in arraysOfWords[index])
{
string str2 = baseString + " " + str;
if (index + 1 < arraysOfWords.Length)
{
combineWordsInternal(str2, index + 1);
}
else
{
strings.Add(str2);
}
}
};
combineWordsInternal(string.Empty, 0);
return strings;
}
Second try... I'm not able to do it in LINQ... A little too much complex to linquize correctly :-)
I'm using a local anonymous function (and showing that it's quite complex to recurse on anonymous functions, because you have to declare them separately)
This is a non-recursive solution which buffers strings as it progresses, to reduce the number of concatenations. Therefore it should also be usable for more arrays.
It also preserves your desired order - the items in the first array will always be at the beginning of the resulting string.
var s1 = new string[] { "A", "B", "C" };
var s2 = new string[] { "1", "2", "3", "4" };
var s3 = new string[] { "-", "!", "?" };
var res = Combine(s1, s2, s3);
And the function in question:
private List<string> Combine(params string[][] arrays)
{
if (arrays.Length == 1)
{
// The trivial case - exit.
return new List<string>(arrays[0]);
}
IEnumerable<string> last = arrays[arrays.Length - 1];
// Build from the last array, progress forward
for (int i = arrays.Length - 2; i >= 0; i--)
{
var buffer = new List<string>();
var current = arrays[i];
foreach (var head in current)
{
foreach (var tail in last)
{
// Concatenate with the desired space.
buffer.Add(head + " " + tail);
}
}
last = buffer;
}
return (List<string>)last;
}
Could you try this method ?
static List<string> CombineWords(string[] wordsOne, string[] wordsTwo)
{
var combinedWords = new List<string>();
for(int x = 0; (x <= wordsOne.Length - 1); ++x)
{
for(int y = 0; (x <= wordsTwo.Length - 1); ++y)
{
combinedWords.Add(string.Format("{0} {1}", wordsOne[x], wordsTwo[y]));
}
}
return combinedWords;
}
Kris