I have some code that doesn't work as expected. As output, I get:
Concatenation.Concatenation+ConcatWord
I have no idea how to make it work as I would like. It should output the biggest concatenation word in the array and the number of its characters. The input might be:
string[] words = {"five","fivetwo","fourfive","fourfivetwo","one","onefiveone","two","twofivefourone"}`
for which the output should be:
"fourfivetwo" with 11 characters
Here's my code
I think something is wrong with this part, but I'm not sure.:
List<ConcatWord> concatWords = new List<ConcatWord>();
for (int i = 0; i < data.Length; i++)
{
ConcatWord concatWord = new ConcatWord(i, data[i]);
for (int j = 0; j < data.Length; j++)
{
if (i != j)
{
if (data[i].Contains(data[j]) && data[i].Length > data[j].Length)
{
concatWord.words.Add(data[j]);
}
}
}
}
Try this:
string[] words = { "five", "fivetwo", "fourfive", "fourfivetwo", "one", "onefiveone", "two", "twofivefourone" };
var allCombinations = words.SelectMany(w => words, (left, right) => left + right);
var combinedWords = words.Where(w => allCombinations.Contains(w));
string longestCombinedWord = combinedWords.OrderByDescending(w => w.Length).First();
Console.WriteLine(longestCombinedWord);
Here's how you can make it shorter
string[] data = { "five","fivetwo","fivetwo","fivetwo","fourfive","fourfivetwo","one","onefiveone","two","twofivefourone" };
string longestWord = data.OrderByDescending(words => words.Length)
.Distinct()
.First();
Console.WriteLine (longestWord);
You could break it apart.
class Program
{
static void Main()
{
var searchTerms = new List<string> {"one", "two", "three", "four", "five"};
var words = new List<string>
{
"five",
"fivetwo",
"fourfive",
"fourfivetwo",
"one",
"onefiveone",
"two",
"twofivefourone"
};
var wordsAndMatches = new Dictionary<string, int>()
{
{"five", 0}, {"fivetwo", 0}, {"fourfive", 0},
{ "fourfivetwo", 0}, {"one", 0}, {"onefiveone", 0},
{"two", 0}, {"twofivefourone", 0}
};
foreach (var word in words)
{
var numberOfMatches = GetNumberOfOccurances(word, searchTerms);
wordsAndMatches[word] = numberOfMatches;
}
foreach (var wordsAndMatch in wordsAndMatches)
{
var result = string.Format("{0} contains {1} number of matches.", wordsAndMatch.Key, wordsAndMatch.Value);
Console.WriteLine(result);
}
var highestNumberOfConcatenations = wordsAndMatches.Values.OrderByDescending(x => x).FirstOrDefault();
var wordWithHighestNumberOfMatches = wordsAndMatches.FirstOrDefault(x => x.Value == highestNumberOfConcatenations);
Console.WriteLine("{0} has the highest number of matches at {1} matches.", wordWithHighestNumberOfMatches.Key, wordWithHighestNumberOfMatches.Value);
}
private static int GetNumberOfOccurances(string word, IEnumerable<string> searchTerms)
{
return searchTerms.Count(word.Contains);
}
}
Related
I'm facing an issue while displaying multiple lists the value in a single row column.
Here is an example of code.
public class Program
{
static void Main(string[] args)
{
Dictionary<string, List<object>> keyvalues = new Dictionary<string, List<object>>();
keyvalues.Add("Code", new List<object>() { 1, 2, 3, 4 });
keyvalues.Add("Name", new List<object>() { "A", "B", "C", "D" });
keyvalues.Add("Age", new List<object>() { 20, 30, 40, 50 });
var listData = keyvalues.Select(x => x.Value).Select((x, i) => new { obj = x, index = i });
var listData = keyvalues.Select((x, iparent) => x.Value.Select((z, i) => new { value = string.Concat(z, x.Value[i]) }).ToList()).ToList();
Console.ReadLine();
}
}
Expected output
1A20
2B30
3C40
4D50
If you are using .Net 6, you could make use of the new 3 way Zip extension.
var result = keyvalues["Code"].Zip(keyvalues["Name"], keyvalues["Age"])
.Select(x=> $"{x.First}{x.Second}{x.Third}");
Why make it so complicated?
for(int x = 0; x<keyValues["Code"].Count; x++)
Console.WriteLine(
keyValues["Code"][x]+
keyValues["Name"][x]+
keyValues["Age"][x]
);
LINQ's a hammer; not every problem is a nail.
ps if you have N keys, you can easily turn it into a
var keys = new[]{"Code","Name","Age","Foo","Bar"};
for(...)
foreach(var k in keys)
... //some concat here or use the values directly eg adding to your page
You could easily use Zip here. However, you could roll your own
public static IEnumerable<string> DoStuff<T, T2>(Dictionary<T, List<T2>> source)
{
var max = source.Values.Max(x => x?.Count ?? 0);
for (var i = 0; i < max; i++)
yield return string.Concat(source.Values.Select(x => x.ElementAtOrDefault(i)));
}
Usage
var results = DoStuff(keyvalues);
Console.WriteLine(string.Join(Environment.NewLine,results));
Output
1A20
2B30
3C40
4D50
or
public static IEnumerable<string> DoStuff<T>(List<T>[] source)
{
var max = source.Max(x => x?.Count ?? 0);
for (var i = 0; i < max; i++)
yield return string.Concat(source.Select(x => x.ElementAtOrDefault(i)));
}
...
var results = DoStuff(keyvalues.Values.ToArray());
Console.WriteLine(string.Join(Environment.NewLine,results));
I want to make a string array with values of names and some numbers(which are strings)
i want to pass them into a function that will take the array and then split them into an object jagged array (1 array of strings and 1 array of ints)
the array is:
string[] str= { "toto", "the", "moto", "my", "friend","12","13","14","99","88"};
and the function looks like this:
public object[][] bloop (string[] bstr)
{
}
whats next?
Your scenario looks like bad design that can cause errors and performance issues. The better way is to change code for using generic List<> or something like that. But in your current problem you can use below code:
public object[][] bloop (string[] bstr)
{
var numbers = new List<int>();
var strings = new List<string>();
var result = new object[2][];
foreach(var str in bstr)
{
int number = 0;
if(int.TryParse(str, out number))
{
numbers.Add(number);
}
else
{
strings.Add(str);
}
}
result[0] = strings.ToArray();
result[1] = numbers.ToArray();
return result;
}
public static object[][] bloop(string[] bstr)
{
object[][] result = new object[2][] { new object[bstr.Length], new object[bstr.Length] };
int sFlag = 0, iFlag = 0, val;
foreach (string str in bstr)
if (int.TryParse(str, out val))
result[1][iFlag++] = val;
else
result[0][sFlag++] = str;
return result;
}
I agree that your requirement sounds odd and should be solved with a different approach. However, this will do what you want:
public T[][] Bloop<T>(T[] items)
{
if (items == null) throw new ArgumentNullException("items");
if (items.Length == 1) return new T[][] { items, new T[] { } };
int firstLength = (int) Math.Ceiling((double)items.Length / 2);
T[] firstPart = new T[firstLength];
Array.Copy(items, 0, firstPart, 0, firstLength);
int secondLength = (int)Math.Floor((double)items.Length / 2);
T[] secondPart = new T[secondLength];
Array.Copy(items, firstLength, secondPart, 0, secondLength);
return new T[][] { firstPart, secondPart };
}
Your sample:
string[] str= { "toto", "the", "moto", "my", "friend","12","13","14","99","88"};
string[][] result = Bloop(str);
If you need the second array as int[] you could use following:
int[] ints = Array.ConvertAll(result[1], int.Parse);
Linq solution.
You have two groups: first one has items that can be parsed to int and the second group contains all the others, so GroupBy looks quite naturally:
public Object[][] bloop(string[] bstr) {
if (null == bstr)
throw new ArgumentNullException("bstr");
int v;
return bstr
.GroupBy(x => int.TryParse(x, out v))
.OrderBy(chunk => chunk.Key) // let strings be the first
.Select(chunk => chunk.ToArray())
.ToArray();
}
Test:
string[] str = { "toto", "the", "moto", "my", "friend", "12", "13", "14", "99", "88" };
// toto, the, moto, my, friend
// 12, 13, 14, 99, 88
Console.Write(String.Join(Environment.NewLine,
bloop(str).Select(x => String.Join(", ", x))));
It need to sort a string array like this to a special format. Our Array is:
input1 = new string[12]{"Active1","12","mm","Active2","17","mm","Width","25","mil","Height","20","mil"}
and our desired sort list is:
sort = new string[6]{"Serial","Width","Height","Active1","Active2","Time"}
My valid format for output is this:
Output = [{Serial,null,null},{Width,25,mil},{Height,20,mil},{Active1,12,mm},{Active2,17,mm},{Time,null,null}]
It is necessary to set null value for data that don't exist in Input Array.
I'm using this code for my purpose:
var Output = (from i in Enumerable.Range(0, input.Length / 3)
let index = Array.IndexOf(sort, input[i * 3])
where index >= 0
select ne3w string[] { input[i * 3], input[i * 3 + 1] , input[i * 3 + 2]})
.OrderBy(a => Array.IndexOf(sort, a[0])).ToArray();
but it doesn't show the values that don't exist in input Array.
I would put this into a separate method:
private static IEnumerable<string[]> TransformInput(string[] input)
{
return from key in new[] { "Serial", "Width", "Height", "Active1", "Active2", "Time" }
let keyIndex = Array.IndexOf(input, key)
let hasData = keyIndex > 1
select new[]
{
key,
hasData ? input[keyIndex + 1] : null,
hasData ? input[keyIndex + 2] : null
};
}
And then use it as follows:
var input1 = new string[12]
{ "Active1", "12", "mm", "Active2", "17", "mm", "Width", "25", "mil", "Height", "20", "mil" };
var sorted = TransformInput(input1);
You can do it with the method below:
private string[][] Sort(string[] input)
{
List<string> inputList = new List<string> ();
inputList = input.ToList<string> ();
List<string[]> sortedList = new List<string[]> ();
string[] sort = new string[]{"Serial", "Width", "Height", "Active1", "Active2", "Time"};
foreach(string key in sort)
{
if (inputList.Contains<string> (key)) {
int i = inputList.IndexOf (key);
string[] t = new string[]{inputList[i],inputList[i+1],inputList[i+2]};
sortedList.Add (t);
}
else
{
string[] t = new string[]{key,null, null};
sortedList.Add (t);
}
}
return sortedList.ToArray<string[]> ();
}
Hope it help you out!
Given the two sets of input data:
var input1 = new string[12]
{
"Active1","12","mm",
"Active2","17","mm",
"Width","25","mil",
"Height","20","mil"
};
var sort = new string[6]
{
"Serial","Width","Height","Active1","Active2","Time"
};
This worked for me:
var lookup =
input1
.Select((x, n) => new { x, n })
.ToLookup(xn => xn.n / 3)
.ToLookup(
z => z.ElementAt(0).x,
z => z.Skip(1).Select(w => w.x));
var result =
sort
.Select(x =>
new [] { x }
.Concat(lookup[x].SelectMany(z => z))
.Concat(new string[] { null, null })
.Take(3)
.ToArray())
.ToArray();
I got this result:
Building on Nitesh, but removing the need to scan input repeatedly by using a dictionary
using System.Linq; //at top of file
private static string[][] TransformInput(string[] input)
{
var sortOrder = new[] { "Serial", "Width", "Height", "Active1", "Active2", "Time" };
//dictionary pointing words to position in input
var inputDict = Enumerable.Range(0, input.Length/3)
.Select(i => i*3).ToDictionary(i => input[i]);
//Try to read position from dictionary; return nulls if fail
return sortOrder.Select(x => {
int i;
return (inputDict.TryGetValue(x, out i))
? new[]{x, input[i+1], input[i+2]}
: new[]{x, null, null};
}).ToArray();
}
I think this code is good for your problem.
static List<string[]> SortedList(string[] input)
{
var sort = new string[6] { "Serial", "Width", "Height", "Active1", "Active2", "Time" };
List<string[]> output = new List<string[]>();
for (int i = 0; i < sort.Length; i++)
{
var findIndex = input.ToList().IndexOf(sort[i]);
if (findIndex != -1)
output.Add(new string[3]
{
input[findIndex],
input[findIndex + 1],
input[findIndex + 2]
});
else
output.Add(new string[3]
{
sort[i],
null,
null
});
}
return output;
}
And now you call that method:
var input = new string[12] { "Active1", "12", "mm", "Active2", "17", "mm", "Width", "25", "mil", "Height", "20", "mil" };
var output = SortedList(input);
How would I loop through two arays using a foreach loop?
I found this previously, but that's for PHP not c#
$images = array('image1', 'image2', ...);
$descriptions = array('description1', 'description2', ...);
foreach (array_combine($images, $descriptions) as $image => $desc) {
echo $image, $desc;
}
my thought is to have something like the following
string[] ValueA = {1,2,3}
string[] ValueB = (a,b,c}
foreach(something here from ValueA && ValueB)
{
methodNameHere(ValueA, ValueB); //method I am calling requires the two values
}
You will be Zip operation that come in .Net 4 in feature. This on link1 and link2 is description.
You will be right something like:
var alpha = new [] { A, B, C, D };
var day = new [] { "s", "s", "m", "t" };
var alphasAndDays = alpha.Zip(day, (n, w) => new { Alpha = n, Day = w });
foreach(var ad in alphasAndDays)
{
Console.WriteLine(aw.Alpha + aw.Day);
}
A simple reiteration can do that:
class Program
{
static void Main(string[] args)
{
string[] setA = new string[3] {"1", "2", "3"};
string[] setB = new string[3] { "a", "b", "c" };
foreach (string val1 in setA) {
foreach (string val2 in setB) {
Program test = new Program();
String printer = test.concatString(val1, val2);
Console.WriteLine(printer);
}
}
Console.ReadLine();
}
public string concatString(string value1, string value2) {
String value3 = value1 + value2;
return value3;
}
}
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);
foreach (var item in numbersAndWords)
Console.WriteLine(item);
// This code produces the following output:
// 1 one
// 2 two
// 3 three
I have a string that might look something like this: "3, 7, 12-14, 1, 5-6"
What i need to do is to change that into a string looking like this: "1, 3, 5, 6, 7, 12, 13, 14"
I have made the following code work, but i would very much appreciated help how to do this a cleaner way with less lines of code:
private string sortLanes(string lanesString)
{
List<string> sortedLanes = new List<string>();
if (lanesString.Contains(',') || lanesString.Contains('-'))
{
List<string> laneParts = lanesString.Split(',').ToList();
foreach (string lanePart in laneParts)
{
if (lanePart.Contains('-'))
{
int splitIndex = lanePart.IndexOf('-');
int lanePartLength = lanePart.Length;
int firstLane = Convert.ToInt32(lanePart.Substring(0, splitIndex));
int lastLane = Convert.ToInt32(lanePart.Substring(splitIndex + 1, lanePartLength - splitIndex - 1));
while (firstLane != lastLane)
{
sortedLanes.Add(firstLane.ToString().Trim());
firstLane++;
}
sortedLanes.Add(lastLane.ToString());
}
else
{
sortedLanes.Add(lanePart.Trim());
}
}
sortedLanes.Sort();
sortedLanes = sortedLanes.OrderBy(x => x.Length).ToList();
lanesString = "";
foreach (string lane in sortedLanes)
{
if (lanesString.Length == 0)
{
lanesString = lane;
}
else
{
lanesString = lanesString + ", " + lane;
}
}
}
else
{
return lanesString;
}
return lanesString;
}
I would first split by the , then convert each value into either a single integer or the desired range. Take the results and reorder them and then concatenate back into a string. Something like this.
string test = "3, 7, 12-14, 1, 5-6";
var items = test.Split(',');
var ints = items.SelectMany(item => Expand(item));
string result = string.Join(", ", ints.OrderBy(i => i).ToArray());
private static IEnumerable<int> Expand(string str)
{
if (str.Contains('-'))
{
var range = str.Split('-');
int begin = int.Parse(range[0]);
int end = int.Parse(range[1]);
for (int i = begin; i <= end; i++)
yield return i;
}
else
yield return int.Parse(str);
}
Of course you might want to add some error checking, but I'll leave that up to you.
This will produce the wanted result (partially based on the incorrect answer from #Tigran):
var parts = "3, 7, 12-14, 1, 5-6".Split(new string[] {", "}, StringSplitOptions.None).ToList();
var finalResult = new List<int>();
foreach(var item in parts)
{
if(item.Contains("-"))
{
var rangeParts = item.Split('-');
var first = int.Parse(rangeParts[0]);
var second = int.Parse(rangeParts[1]);
var result = Enumerable.Range(first, second - first + 1);
finalResult.AddRange(result);
}
else
{
finalResult.Add(int.Parse(item));
}
}
var sorted = finalResult.OrderBy(i => i);
var resultString = string.Join(", ", sorted);
Regex would work nicely here...
static void Main()
{
Assert.AreEqual("1, 3, 5, 6, 7, 12, 13, 14", Transform("3, 7, 12-14, 1, 5-6"));
}
private static string Transform(string input)
{
StringBuilder sb = new StringBuilder();
foreach(Match m in new Regex(#"(?<start>\d+)(?:-(?<end>\d+))?(?:,|$)\s*").Matches(input)
.OfType<Match>().OrderBy(m => int.Parse(m.Groups["start"].Value)))
{
int start = int.Parse(m.Groups["start"].Value);
int end = !m.Groups["end"].Success ? start : int.Parse(m.Groups["end"].Value);
foreach (int val in Enumerable.Range(start, end - start + 1))
sb.AppendFormat("{0}, ", val);
}
if (sb.Length > 0)
sb.Length = sb.Length - 2;//remove trailing comma+space;
return sb.ToString();
}
Update
If I wanted to make it confusing I'd just use a single line of code:
return String.Join(", ",new Regex(#"(?<start>\d+)(?:-(?<end>\d+))?(?:,|$)\s*").Matches(input)
.OfType<Match>().OrderBy(m => int.Parse(m.Groups["start"].Value)).SelectMany(m =>
Enumerable.Range(int.Parse(m.Groups["start"].Value), int.Parse(m.Groups["end"].Success
? m.Groups["end"].Value : m.Groups["start"].Value) - int.Parse(m.Groups["start"].Value) + 1))
.Select(i => i.ToString()).ToArray());
LoL :)
If you like Linq:
string input = "3, 7, 12-14, 1, 5-6";
List<int> all = input.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(r => new
{
Range = r,
Parts = r.Split(new[] { '-' }, StringSplitOptions.RemoveEmptyEntries)
.Select(p => int.Parse(p))
})
.SelectMany(x => Enumerable.Range(x.Parts.First(), 1 + x.Parts.Last() - x.Parts.First()))
.ToList();
Demo