I want to find two longest words from array ,made from smaller words. my code are given below.
current out put is:
catxdogcatsrat, ratcatdogcat, catsdogcats, dogcatsdog
required output is:
ratcatdogcat, catsdogcats
class program
{
public static void Main(String[] args)
{
List<string> list2 = new List<string>();
string[] stringrray = { "cat", "cats", "catsdogcats", "catxdogcatsrat", "dog", "dogcatsdog",
"hippopotamuses", "rat", "ratcatdogcat" };
list2.Add(stringrray[0]);
list2.Add(stringrray[1]);
list2.Add(stringrray[2]);
list2.Add(stringrray[3]);
list2.Add(stringrray[4]);
list2.Add(stringrray[5]);
list2.Add(stringrray[6]);
list2.Add(stringrray[7]);
list2.Add(stringrray[8]);
List<string> list = new List<string>();
var mod = list2.OrderByDescending(x => x.Length).ToList();
int j = 1;
for (int k = 0; k < mod.Count; k++)
{
for (int i = 0; i < mod.Count-j; i++)
{
if (mod[i].Contains(mod[mod.Count - j]))
{
j++;
list.Add(mod[i]);
}
}
}
var mod1 = list.OrderByDescending(x => x.Length);
foreach (var i in mod1)
{
Console.WriteLine(i);
}
Console.ReadLine();
}
}
I think you are looking for something like this
string[] stringrray = { "cat", "cats", "catsdogcats", "catxdogcatsrat", "dog", "dogcatsdog", "hippopotamuses", "rat", "ratcatdogcat" };
List<string> list2 = new List<string>(stringrray);
List<string> Finallist = new List<string>();
char[] smallstrchar = String.Join("", list2.Where(x => x.Length <= 4)).ToCharArray();
char[] bigstrchar = String.Join("", list2.Where(x => x.Length > 4)).ToCharArray();
char[] modchar = bigstrchar.Except(smallstrchar).ToArray();
foreach(string bigstr in list2)
{
if(!(bigstr.IndexOfAny(modchar) != -1))
{
Finallist.Add(bigstr);
}
}
Finallist = Finallist.OrderByDescending(x => x.Length).Take(2).ToList();
foreach(string finalstr in Finallist)
{
Console.WriteLine(finalstr);
}
So first is the stringrray which contains all the strings which are supposed to be taken care and find the longest one out of it. With your code it also takes the string which contains x in them but all other chars are matched. So I have made a list of strings in list2 which contains all the values. Then splitted the list2 in 2 parts that is smallstrchar array contains all the chars of the smaller strings less than length of 4 and Bigstrchar contains all chars of strings which are bigger than length of 5. Now Except takes out all the chars which does not exsist in the smallstrchar and present in Bigstrchar. Now we have the list of chars which need to be excluded from the sort.
Finally IndexOfAny to find in that string contains that char or not. If not then add to Finallist. Later we can take 2 from the list.
Hope this helps
You could simplify adding the array to list2 with
list2.AddRange(stringrray)
You may use this code...
static void Main(string[] args)
{
List<string> words = new List<string>() { "cat", "cats", "catsdogcats", "catxdogcatsrat", "dog", "dogcatsdog", "hippopotamuses", "rat", "ratcatdogcat" };
List<string> result = new List<string>();
// solution 1
foreach (string word in words)
{
if (IsCombinationOf(word, words))
{
result.Add(word);
}
}
// solution 2
result = words.Where(x => IsCombinationOf(x, words)).ToList();
}
public static bool IsCombinationOf(string word, List<string> parts)
{
// removing the actual word just to be secure.
parts = parts.Where(x => x != word).OrderByDescending(x => x.Length).ToList();
// erase each part in word. Only those which are not in the list will remain.
foreach (string part in parts)
{
word = Regex.Replace(word, part, "");
}
// if there are any caracters left, it hasn't been a combination
return word.Length == 0;
}
but...
This code has a little bug. The OrderbyDescending clause ensures that cats will be removed before cat. Otherwise the s would remain and the code wouldn't work as expected. But if we use some fictional values this code will not work properly. For example:
List<string> words = new List<string>() { "abz", "e", "zefg", "f", "g", "abzefg" };
Let's have a look at abzef. The algorithm will remove zefg first, but then it's not possible to go any futher. Indeed, the word is a combination of abz, e, f and g .
Related
I have a list of strings and a char array of letters. And I want to display the strings that contain all the chars from the array in the string.
List-list of strings
charsArray-array of chars
Final-the final list with the sorted words
Example
charsArray {'a','e','i','z'}
List {"abcde","iertaz","aio","zzeml","amoioze"}
Final(output) iertaz amoioze
I tried this
foreach(string word in List)
{
bool contain = true;
foreach (char letter in charsArray}
{
if (word.Contains(letter) && contain)
{
Final.Add(word);
}
else
{
contain = false;
}
}
}
foreach (string word in Final)
{
Console.WriteLine(word);
}
Having
char[] chars = new char[] {
'a','e','i','z'};
List<string> list = new List<string>() {
"abcde", "iertaz", "aio", "zzeml", "amoioze" };
We can try subtracting word from chars: if all characters from chars are removed, the word is what we want:
using System.Linq;
...
var result = list
.Where(word => !chars.Except(word).Any())
.ToList();
This solution uses All:
var charsArray = new char[] { 'a', 'e', 'i', 'z' };
var L = new[] { "abcde","iertaz","aio","zzeml","amoioze"}.ToList();
var final = L.Where(word => charsArray.All(a => word.Contains(a))).ToList();
The result is correct:
iertaz
amoioze
How about this, demonstrated here
public static IEnumerable<IEnumerable<T>> ContainsAll<T>(
this IEnumerable<IEnumerable<T>> source,
IEnumerable<T> search,
IEqualityComparer<T> comparer = default)
{
ArgumentNullException.ThrowIfNull(source);
ArgumentNullException.ThrowIfNull(search);
comparer ??= EqualityComparer<T>.Default;
var searchSet = search is HashSet<T> ss && ss.Comparer == comparer
? ss
: new HashSet<T>(search, comparer);
return source.Where(item => searchSet.IsSubsetOf(item));
}
That you can use like this,
var words = new[] {"abcde","iertaz","aio","zzeml","amoioze"};
var search = new[] {'a','e','i','z'};
foreach (string match in words.ContainsAll(search))
{
Console.WriteLine(match);
}
In this line you are adding the word if the first character is in the word because contain is true
...
if (word.Contains(letter) && contain)
{
Final.Add(word);
}
...
you are almost there, you just need a little modification to avoid the mistake above
foreach(string word in List)
{
bool contain = true;
foreach (char letter in charsArray}
{
if (!word.Contains(letter))
{
contain = false;
}
}
if (contain)
{
Final.Add(word);
}
}
foreach (string word in Final)
{
Console.WriteLine(word);
}
You want to find strings that contain all the chars from charsArray. It means every char in charsArray should be contained by the target string.
using System.Linq;
var List = new List<string>() { "abcde", "iertaz", "aio", "zzeml", "amoioze" };
var charsArray = new char[] { 'a','e','i','z' };
var result = List.FindAll(word => charsArray.All(letter => word.Contains(letter)));
I have a list of strings (word--number) ex (burger 5$). I need to extract only numbers from every string in list and make new int list.
There are several ways to do that, Regex and Linq for example.
For short string you can use Linq, for example:
public static void Main()
{
var myStringValue = "burger 5$";
var numbersArray = myStringValue.ToArray().Where(x => char.IsDigit(x));
foreach (var number in numbersArray)
{
Console.WriteLine(numbersArray);
}
}
If you take a look at the Regex.Split, numbers article.
You'll find the answer in there. Modified code might look like
var source = new List<string> {
"burger 5$",
"pizza 6$",
"roll 1$ and salami 2$"
};
var result = new List<int>();
foreach (var input in source)
{
var numbers = Regex.Split(input, #"\D+");
foreach (string number in numbers)
{
if (Int32.TryParse(number, out int value))
{
result.Add(value);
}
}
}
Hope it helps.
Petr
Using linq and Regex:
List<string> list = new List<string>(){"burger 5$","ab12c","12sc34","sd3d5"};
Regex nonDigits = new Regex(#"[^\d]");
List<string> list2 = list.Select(l => nonDigits.Replace(l, "")).ToList();
You can take a look and also solve the problem with this code:
List<string> word_number = new List<string>();
List<int> number = new List<int>();
word_number.Add("burger 5$");
word_number.Add("hamburger 6$");
word_number.Add("burger 12$");
foreach (var item in word_number)
{
string[] parts = item.Split(' ');
string[] string_number = parts[1].Split('$');
number.Add(Convert.ToInt16(string_number[0]));
Console.WriteLine(string_number[0]);
}
Below is the logic that i tried to implement and able to sort it but need to figure out to ignore special characters in it
My Logic:
Reversed string in a list
Sorted in ascending order
Again reversed back sorted strings &
Finally returned as a string by joining with ~ delimiter.
List<String> inputLst= new List<String>() { "Bananas!", "Cherry2",
"Mango","Apples", "Grape$", "Guava" };
List<String> sortList = new List<String>();
List<String> outputList = new List<String>();
foreach (String str in inputLst)
{
sortList.Add(new String(str.ToCharArray().Reverse().ToArray()));
}
sortList.Sort();
foreach (String str in sortList)
{
outputList.Add(new String(str.ToCharArray().Reverse().ToArray()));
}
Return String.Join("~", outputList);
Output i got is Bananas!~Grape$~Cherry2~Guava~Mango~Apples
Expected output should be Guava~Grape$~Mango~Bananas!~Apples~Cherry2
Could anyone please suggest me optimized solution to sort a list by last character by ignoring special characters? Here i used 2 lists for string reversals, can it be done in more efficient way?
Note: without using LINQ pls.
With a bit of LINQ and Regex, this can be achieved relatively simply:
var inputList = new List<string>() { "Bananas!", "Cherry2", "Mango","Apples", "Grape$", "Guava" };
var outputList = inputList.OrderBy(s => new string(Regex.Replace(s, "[^a-zA-Z]", "")
.Reverse()
.ToArray()))
.ToList();
var output = String.Join("~", outputList);
EDIT: Non-LINQ approach:
var inputList = new List<string>() { "Bananas!", "Cherry2", "Mango", "Apples", "Grape$", "Guava" };
inputList.Sort(new ReverseStringComparer());
var output = String.Join("~", inputList);
ReverseStringComparer:
class ReverseStringComparer : IComparer<string>
{
public int Compare(string x, string y)
{
string a = new string(Regex.Replace(x, "[^a-zA-Z]", "").Reverse().ToArray());
string b = new string(Regex.Replace(y, "[^a-zA-Z]", "").Reverse().ToArray());
return a.CompareTo(b);
}
}
Solution without regex:
string foo()
{
List<String> inputLst= new List<String>() { "Bananas!", "Cherry2", "Mango","Apples", "Grape$", "Guava" };
inputLst.Sort((l, r) => new string(l.Reverse().SkipWhile( x => !char.IsLetter(x) ).ToArray()).CompareTo( new string(r.Reverse().SkipWhile(x => !char.IsLetter(x)).ToArray()) ) );
return String.Join("~", inputLst);
}
To skip all non letter chars (and not only at the beginning of string) as suggested in comment, just use Where instead of SkipWhile like this:
string bar()
{
List<String> inputLst= new List<String>() { "Bananas!", "Cherry2", "Mango","Apples", "Grape$", "Guava" };
inputLst.Sort((l, r) => new string(l.Reverse().Where( x => char.IsLetter(x) ).ToArray()).CompareTo( new string(r.Reverse().Where(x => char.IsLetter(x)).ToArray()) ) );
return String.Join("~", inputLst);
}
Notice Where has invers logic (char.IsLetter(x)) compare to SkipWhile (!char.IsLetter(x)).
Find the last symbol being the letter and sort by it.
var inputList = new List<string>() {
"Bananas!", "Cherry2", "Mango","Apples", "Grape$", "Guava" };
var outputList = inputList.OrderBy(s => s.Last(c => char.IsLetter(c)));
Console.WriteLine(string.Join("~", outputList));
Reverse is not needed.
I have an array statsname as
apple
X
banana
Y
Kiwi
z
I need to put apple,banana and Kiwi in an array Fruits and X,Y and Z in an array called alphabets.
Any simple C# mechanism for it please ?
Use the IEnumerable<T>.Where overload which supplies the index.
var fruits = statsname.Where((s, i) => i % 2 == 0).ToArray();
var alphabets = statsname.Where((s, i) => i % 2 != 0).ToArray();
Stolen from How to get Alternate elements using Enumerable in C#
var fruits = myArray.Where((t, i) => i % 2 == 0).ToArray();
var alphabets = myArray.Where((t, i) => i % 2 == 1).ToArray();
If i have understood you question correctly what you want is very simple:
You want put fruits in array of fruits and same for alphabets and they are appearing alternatively in array statsname so:
for(int i=0,j=0;i<statsname.length;i+2,j++)
fruits[j]=statsname[i];
for(int i=1,j=0;i<statsname.length;i+2,j++)
alphabets[j]=statsname[i];
Single LINQ:
List<string> list = new List<string>() { "apple", "X", "banana", "Y", "Kiwi", "z" };
var result = list.Select((l, i) => new { l, i })
.GroupBy(p => p.i % 2)
.Select(x => x.Select(v => v.l).ToList())
.ToList();
Then you have a list of lists:
list<string> fruits = new List<string>();
list<string> alphabet = new List<string>();
for (int i = 0; i < array.Length; i++)
{
if (i % 2 == 0)
fruits.Add(array[i]);
else
alphabet.Add(array[i]);
}
Then you can just do .ToArray on the lists
string[] rawarray = new string [] {"Apple","X" .....};
string[] Fruites = new string[rawarray.Length/2+1];
string[] Alphabets = new string[rawarray.Length/2];
For(int i=0; i<rawarray.Length;i++)
{
if(i%2==0)
{
Fruits[i/2]=rawarray[i];
}
else
{
Alphabets[i/2]=rawarray[i];
}
}
using only Arrays:
var array = new string[] { "apple", "X", "banana", "Y", "Kiwi", "z" };
var fruit = new string[array.Length];
var alphabet = new string[array.Length];
for(var i = 0,j = 0; i < array.Length / 2; i++, j += 2)
{
fruit[i] = array[j];
alphabet[i] = array[j + 1];
}
You could make an iterator which just skips every other element. The idea is to have a "view" of a collection, special enumerable which will return only some of the elements:
static IEnumerable<T> everyOther<T>( IEnumerable<T> collection )
{
using( var e = collection.GetEnumerator() ) {
while( e.MoveNext() ) {
yield return e.Current;
e.MoveNext(); //skip one
}
}
}
You can use System.Linq.Skip to skip the first element.
string[] words = "apple X banana Y Kiwi z".Split();
var fruits = everyOther( words );
var alphabets = everyOther( words.Skip(1) );
Just use them as a new collection or call .ToArray() or .ToList() on them:
foreach( string f in fruits )
Console.WriteLine( f );
string[] anArray = fruits.ToArray(); //using System.Linq
Now you have what you need.
Iterators are methods which yield return, see Iterators (C# Programming Guide). This is very strong feature of the language. You can:
skip elements
decorate elements
change ordering
concatenate sequences (see System.Linq.Concat)
...
Here is some working code, hopefully this will be helpfull to you:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ReadFile
{
class Program
{
static void ReadFile(string filePath, List<string> custumerNames, List<int> phoneNumbers)
{
string line = string.Empty;
var fileStream = new StreamReader(filePath);
bool isPhoneNumber = true;
while ((line = fileStream.ReadLine()) != null)
{
if (isPhoneNumber)
{
phoneNumbers.Add(Convert.ToInt32(line));
isPhoneNumber = false;
}
else
{
custumerNames.Add(line);
isPhoneNumber = true;
}
}
fileStream.Close();
}
static void Main(string[] args)
{
Console.WriteLine("Started reading the file...");
List<string> custumersNamesList = new List<string>();
List<int> custumersPhonesNumbers = new List<int>();
ReadFile("SampleFile.txt", custumersNamesList, custumersPhonesNumbers);
//Assuming both the list's has same lenght.
for (int i = 0; i < custumersNamesList.Count(); i++)
{
Console.WriteLine(string.Format("Custumer Name: {0} , Custumer Phone Number: {1}",
custumersNamesList[i], Convert.ToString(custumersPhonesNumbers[i])));
}
Console.ReadLine();
}
}
}
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