C# union with string - c#

I have 2 string (files path exactly) like this :
C:\aaaa\bbbb\cccc
and
cccc\dddd.
I would like to merge the two strings with an union operation.
For obtain :
C:\aaaa\bbbb\cccc\dddd
How to do it ? I don't find a string method for this.
Do you think i search in the good direction or i should try with another method (split string...) ?
Thanks

How about this:
var path1 = #"C:\aaaa\bbbb\cccc";
var path2 = #"cccc\dddd";
var x = string.Join(
new string(Path.DirectorySeparatorChar, 1),
path1.Split(Path.DirectorySeparatorChar)
.Concat(path2.Split(Path.DirectorySeparatorChar))
.Distinct()
.ToArray());
// path1 = C:\aaaa\bbbb\cccc
// path2 = cccc\dddd
// result = C:\aaaa\bbbb\cccc\dddd
// path1 = C:\aaaa\bbbb\cccc\dddd
// path2 = cccc\dddd
// result = C:\aaaa\bbbb\cccc\dddd

this can get you started. There a lot of scenarios you could CYA over , but essentially find where string two overlaps string one, then join them.
public static void Main()
{
string one = #"C:\aaaa\bbbb\cccc";
string two = #"cccc\dddd";
int overlapIndex = one.IndexOf(two.Split('\\').First());
string three = one.Substring(0, overlapIndex) + two;
Console.WriteLine(three);
// "C:\aaaa\bbbb\cccc\dddd"
}

I think there are some good solutions already, just for my own reference i made a function that does this on any two strings.
Sorry that it got a litle bloated.
public string Union(string one, string two)
{
if (one == null || two == null)
return null;
int idxOne = -1;
int j = one.Length - 1;
for (int i = two.Length - 1; i >= 0; i--)
{
if (two[i] == one[j]) // if the current index of string 2 matches the last character of string one, start counting
{
j--;
idxOne = j;
}
else if (i > 0)
{
j = one.Length - 1; // throw away results if match stopped matching half-way in.
idxOne = -1;
}
}
if (idxOne != -1)
{
return one.Substring(0, idxOne + 1) + two;
}
return one + two;
}

Related

Remove duplicates from a string

Say I have a string like this:
anxxnbddc
I want to process this and return a string which contains only the characters which appear in the input string exactly once. Therefore my expected output would be:
abc
I have tried this code:
static string RemoveDuplicates(string key)
{
string result = "";
for (int i = 0; i < key.Length - 1; i++)
{
if (key[i] != key[i + 1])
{
result += key[i];
}
}
return result;
}
but my output is:
anxnbd
How do I get my desired output?
string noDuplicates = new string(input.ToCharArray().Where(c => input.ToCharArray().FindAll(x => x == c).Length == 1).ToArray());
Do this with Linq approach:
string withoutDuplicates= new string(yourString.ToCharArray().Distinct().ToArray());
Must help

Using indexOf (C#) to remove a set of characters from a string

public static string shita1(string st1)
{
string st2 = "", stemp = st1;
int i;
for(i=0; i<stemp.Length; i++)
{
if (stemp.IndexOf("cbc") == i)
{
i += 2 ;
stemp = "";
stemp = st1.Substring(i);
i = 0;
}
else
st2 = st2 + stemp[i];
}
return st2;
}
static void Main(string[] args)
{
string st1;
Console.WriteLine("enter one string:");
st1 = Console.ReadLine();
Console.WriteLine(shita1(st1));
}
}
i got a challange from my college, the challange is to move any "cbc" characters from a string...
this is my code... it works when i use only one "cbc" but when i use 2 of them it stucks... help please :)
The IndexOf Method gives you everything you need to know.
Per the documentation.
Reports the zero-based index of the first occurrence of a specified
Unicode character or string within this instance. The method returns
-1 if the character or string is not found in this instance.
This means you can create a loop that repeats as long as the returned index is not -1 and you don't have to loop through the string testing letter by letter.
I think this should work just tested it on some examples. Doesn't use string.Replace or IndexOf
static void Main(string[] args)
{
Console.WriteLine("enter one string:");
var input = Console.ReadLine();
Console.WriteLine(RemoveCBC(input));
}
static string RemoveCBC(string source)
{
var result = new StringBuilder();
for (int i = 0; i < source.Length; i++)
{
if (i + 2 == source.Length)
break;
var c = source[i];
var b = source[i + 1];
var c2 = source[i + 2];
if (c == 'c' && c2 == 'c' && b == 'b')
i = i + 2;
else
result.Append(source[i]);
}
return result.ToString();
}
You can use Replace to remove/replace all occurances of a string inside another string:
string original = "cbc_STRING_cbc";
original = original.Replace("cbc", String.Empty);
If you want remove characters from string using only IndexOf method you can use this code.
public static string shita1(string st1)
{
int index = -1;
string yourMatchingString = "cbc";
while ((index = st1.IndexOf(yourMatchingString)) != -1)
st1 = st1.Remove(index, yourMatchingString.Length);
return st1;
}
This code remove all inputs of you string.
But you can do it just in one line:
st1 = st1.Replace("cbc", string.Empty);
Hope this help.

Better way for the special concatenation of two strings

I want to concatenate two strings in such a way, that after the first character of the first string, the first character of second string comes, and then the second character of first string comes and then the second character of the second string comes and so on. Best explained by some example cases:
s1="Mark";
s2="Zukerberg"; //Output=> MZaurkkerberg
if:
s1="Zukerberg";
s2="Mark" //Output=> ZMuakrekrberg
if:
s1="Zukerberg";
s2="Zukerberg"; //Output=> ZZuukkeerrbbeerrgg
I've written the following code which gives the expected output but its seems to be a lot of code. Is there any more efficient way for doing this?
public void SpecialConcat(string s1, string s2)
{
string[] concatArray = new string[s1.Length + s2.Length];
int k = 0;
string final = string.Empty;
string superFinal = string.Empty;
for (int i = 0; i < s1.Length; i++)
{
for (int j = 0; j < s2.Length; j++)
{
if (i == j)
{
concatArray[k] = s1[i].ToString() + s2[j].ToString();
final = string.Join("", concatArray);
}
}
k++;
}
if (s1.Length > s2.Length)
{
string subOne = s1.Remove(0, s2.Length);
superFinal = final + subOne;
}
else if (s2.Length > s1.Length)
{
string subTwo = s2.Remove(0, s1.Length);
superFinal = final + subTwo;
}
else
{
superFinal = final;
}
Response.Write(superFinal);
}
}
I have written the same logic in Javascript also, which works fine but again a lot of code.
var s1 = "Mark";
var s2 = "Zukerberg";
var common = string.Concat(s1.Zip(s2, (a, b) => new[]{a, b}).SelectMany(c => c));
var shortestLength = Math.Min(s1.Length, s2.Length);
var result =
common + s1.Substring(shortestLength) + s2.Substring(shortestLength);
var stringBuilder = new StringBuilder();
for (int i = 0; i < Math.Max(s1.Length, s2.Length); i++)
{
if (i < s1.Length)
stringBuilder.Append(s1[i]);
if (i < s2.Length)
stringBuilder.Append(s2[i]);
}
string result = stringBuilder.ToString();
In JavaScript, when working with strings, you are also working with arrays, so it will be easier. Also + will concatenate for you. Replace string indexing with charAt if you want IE7- support.
Here is the fiddle:
http://jsfiddle.net/z6XLh/1
var s1 = "Mark";
var s2 = "ZuckerFace";
var out ='';
var l = s1.length > s2.length ? s1.length : s2.length
for(var i = 0; i < l; i++) {
if(s1[i]) {
out += s1[i];
}
if(s2[i]){
out += s2[i];
}
}
console.log(out);
static string Join(string a, string b)
{
string returnVal = "";
int length = Math.Min(a.Length, b.Length);
for (int i = 0; i < length; i++)
returnVal += "" + a[i] + b[i];
if (a.Length > length)
returnVal += a.Substring(length);
else if(b.Length > length)
returnVal += b.Substring(length);
return returnVal;
}
Could possibly be improved through stringbuilder
Just for the sake of curiosity, here's an unreadable one-liner (which I have nevertheless split over multiple lines ;))
This uses the fact that padding a string to a certain length does nothing if the string is already at least that length. That means padding each string to the length of the other string will have the result of padding out with spaces the shorter one to the length of the longer one.
Then we use .Zip() to concatenate each of the pairs of characters into a string.
Then we call string.Concat(IEnumerable<string>) to concatenate the zipped strings into a single string.
Finally, we remove the extra padding spaces we introduced earlier by using string.Replace().
var result = string.Concat
(
s1.PadRight(s2.Length)
.Zip
(
s2.PadRight(s1.Length),
(a,b)=>string.Concat(a,b)
)
).Replace(" ", null);
On one line [insert Coding Horror icon here]:
var result = string.Concat(s1.PadRight(s2.Length).Zip(s2.PadRight(s1.Length), (a,b)=>string.Concat(a,b))).Replace(" ", null);
Just off the top of my head, this is how I might do it.
var s1Length = s1.Length;
var s2Length = s2.Length;
var count = 0;
var o = "";
while (s1Length + s2Length > 0) {
if (s1Length > 0) {
s1Length--;
o += s1[count];
}
if (s2Length > 0) {
s2Length--;
o += s2[count];
}
count++;
}
Here's another one-liner:
var s1 = "Mark";
var s2 = "Zukerberg";
var result = string.Join("",
Enumerable.Range(0, s1.Length).ToDictionary(x => x * 2, x => s1[x])
.Concat(Enumerable.Range(0, s2.Length).ToDictionary(x => x * 2+1, x => s2[x]))
.OrderBy(d => d.Key).Select(d => d.Value));
Basically, this converts both strings into dictionaries with keys that will get the resulting string to order itself correctly. The Enumerable range is used to associate an index with each letter in the string. When we store the dictionaries, it multiplies the index on s1 by 2, resulting in <0,M>,<2,a>,<4,r>,<6,k>, and multiplies s2 by 2 then adds 1, resulting in <1,Z>,<3,u>,<5,k>, etc.
Once we have these dictionaries, we combine them with the .Concat and sort them with the .OrderBy,which gives us <0,M>,<1,Z>,<2,a>,<3,u>,... Then we just dump them into the final string with the string.join at the beginning.
Ok, this is the *second shortest solution I could come up with:
public string zip(string s1, string s2)
{
return (string.IsNullOrWhiteSpace(s1+s2))
? (s1[0] + "" + s2[0] + zip(s1.Substring(1) + " ", s2.Substring(1) + " ")).Replace(" ", null)
: "";
}
var result = zip("mark","zukerberg");
Whoops! My original shortest was the same as mark's above...so, second shortest i could come up with! I had hoped I could really trim it down with the recursion, but not so much.
var sWordOne = "mark";// ABCDEF
var sWordTwo = "zukerberg";// 123
var result = (sWordOne.Length > sWordTwo.Length) ? zip(sWordOne, sWordTwo) : zip(sWordTwo, sWordOne);
//result = "zmuakrekrberg"
static string zip(string sBiggerWord, string sSmallerWord)
{
if (sBiggerWord.Length < sSmallerWord.Length) return string.Empty;// Invalid
if (sSmallerWord.Length == 0) sSmallerWord = " ";
return string.IsNullOrEmpty(sBiggerWord) ? string.Empty : (sBiggerWord[0] + "" + sSmallerWord[0] + zip(sBiggerWord.Substring(1),sSmallerWord.Substring(1))).Replace(" ","");
}
A simple alternative without Linq witchcraft:
string Merge(string one, string two)
{
var buffer = new char[one.Length + two.Length];
var length = Math.Max(one.Length, two.Length);
var index = 0;
for (var i = 0; i < length; i ++)
{
if (i < one.Length) buffer[index++] = one[i];
if (i < two.Length) buffer[index++] = two[i];
}
return new string(buffer);
}

C# How can I compare two word strings and indicate which parts are different

For example if I have...
string a = "personil";
string b = "personal";
I would like to get...
string c = "person[i]l";
However it is not necessarily a single character. I could be like this too...
string a = "disfuncshunal";
string b = "dysfunctional";
For this case I would want to get...
string c = "d[isfuncshu]nal";
Another example would be... (Notice that the length of both words are different.)
string a = "parralele";
string b = "parallel";
string c = "par[ralele]";
Another example would be...
string a = "ato";
string b = "auto";
string c = "a[]to";
How would I go about doing this?
Edit: The length of the two strings can be different.
Edit: Added additional examples. Credit goes to user Nenad for asking.
I must be very bored today, but I actually made UnitTest that pass all 4 cases (if you did not add some more in the meantime).
Edit: Added 2 edge cases and fix for them.
Edit2: letters that repeat multiple times (and error on those letters)
[Test]
[TestCase("parralele", "parallel", "par[ralele]")]
[TestCase("personil", "personal", "person[i]l")]
[TestCase("disfuncshunal", "dysfunctional", "d[isfuncshu]nal")]
[TestCase("ato", "auto", "a[]to")]
[TestCase("inactioned", "inaction", "inaction[ed]")]
[TestCase("refraction", "fraction", "[re]fraction")]
[TestCase("adiction", "ad[]diction", "ad[]iction")]
public void CompareStringsTest(string attempted, string correct, string expectedResult)
{
int first = -1, last = -1;
string result = null;
int shorterLength = (attempted.Length < correct.Length ? attempted.Length : correct.Length);
// First - [
for (int i = 0; i < shorterLength; i++)
{
if (correct[i] != attempted[i])
{
first = i;
break;
}
}
// Last - ]
var a = correct.Reverse().ToArray();
var b = attempted.Reverse().ToArray();
for (int i = 0; i < shorterLength; i++)
{
if (a[i] != b[i])
{
last = i;
break;
}
}
if (first == -1 && last == -1)
result = attempted;
else
{
var sb = new StringBuilder();
if (first == -1)
first = shorterLength;
if (last == -1)
last = shorterLength;
// If same letter repeats multiple times (ex: addition)
// and error is on that letter, we have to trim trail.
if (first + last > shorterLength)
last = shorterLength - first;
if (first > 0)
sb.Append(attempted.Substring(0, first));
sb.Append("[");
if (last > -1 && last + first < attempted.Length)
sb.Append(attempted.Substring(first, attempted.Length - last - first));
sb.Append("]");
if (last > 0)
sb.Append(attempted.Substring(attempted.Length - last, last));
result = sb.ToString();
}
Assert.AreEqual(expectedResult, result);
}
Have you tried my DiffLib?
With that library, and the following code (running in LINQPad):
void Main()
{
string a = "disfuncshunal";
string b = "dysfunctional";
var diff = new Diff<char>(a, b);
var result = new StringBuilder();
int index1 = 0;
int index2 = 0;
foreach (var part in diff)
{
if (part.Equal)
result.Append(a.Substring(index1, part.Length1));
else
result.Append("[" + a.Substring(index1, part.Length1) + "]");
index1 += part.Length1;
index2 += part.Length2;
}
result.ToString().Dump();
}
You get this output:
d[i]sfunc[shu]nal
To be honest I don't understand what this gives you, as you seem to completely ignore the changed parts in the b string, only dumping the relevant portions of the a string.
Here is a complete and working console application that will work for both examples you gave:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string a = "disfuncshunal";
string b = "dysfunctional";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < a.Length; i++)
{
if (a[i] != b[i])
{
sb.Append("[");
sb.Append(a[i]);
sb.Append("]");
continue;
}
sb.Append(a[i]);
}
var str = sb.ToString();
var startIndex = str.IndexOf("[");
var endIndex = str.LastIndexOf("]");
var start = str.Substring(0, startIndex + 1);
var mid = str.Substring(startIndex + 1, endIndex - 1);
var end = str.Substring(endIndex);
Console.WriteLine(start + mid.Replace("[", "").Replace("]", "") + end);
}
}
}
it will not work if you want to display more than one entire section of the mismatched word.
You did not specify what to do if the strings were of different lengths, but here is a solution to the problem when the strings are of equal length:
private string Compare(string string1, string string2) {
//This only works if the two strings are the same length..
string output = "";
bool mismatch = false;
for (int i = 0; i < string1.Length; i++) {
char c1 = string1[i];
char c2 = string2[i];
if (c1 == c2) {
if (mismatch) {
output += "]" + c1;
mismatch = false;
} else {
output += c1;
}
} else {
if (mismatch) {
output += c1;
} else {
output += "[" + c1;
mismatch = true;
}
}
}
return output;
}
Not really good approach but as an exercise in using LINQ: task seem to be find matching prefix and suffix for 2 strings, return "prefix + [+ middle of first string + suffix.
So you can match prefix (Zip + TakeWhile(a==b)), than repeat the same for suffix by reversing both strings and reversing result.
var first = "disfuncshunal";
var second = "dysfunctional";
// Prefix
var zipped = first.ToCharArray().Zip(second.ToCharArray(), (f,s)=> new {f,s});
var prefix = string.Join("",
zipped.TakeWhile(c => c.f==c.s).Select(c => c.f));
// Suffix
var zippedReverse = first.ToCharArray().Reverse()
.Zip(second.ToCharArray().Reverse(), (f,s)=> new {f,s});
var suffix = string.Join("",
zippedReverse.TakeWhile(c => c.f==c.s).Reverse().Select(c => c.f));
// Cut and combine.
var middle = first.Substring(prefix.Length,
first.Length - prefix.Length - suffix.Length);
var result = prefix + "[" + middle + "]" + suffix;
Much easier and faster approach is to use 2 for loops (from start to end, and from end to start).

Split a string without separator

I have a string variable with value
"abcdefghijklmnop".
Now I want to split the string into string array with, say, three characters (the last array element may contain fewer) in each array element from the right end.
I.e.,
"a"
"bcd"
"efg"
"hij"
"klm"
"nop"
What is the easiest and simplest way to do this?? (Both Visual Basic and C# code is welcome)?
Here's a solution:
var input = "abcdefghijklmnop";
var result = new List<string>();
int incompleteGroupLength = input.Length % 3;
if (incompleteGroupLength > 0)
result.Add(input.Substring(0, incompleteGroupLength));
for (int i = incompleteGroupLength; i < input.Length; i+=3)
{
result.Add(input.Substring(i, 3));
}
It gives the expected output of:
"a"
"bcd"
"efg"
"hij"
"klm"
"nop"
Here's something that works - wrapped up into a string extension function.
namespace System
{
public static class StringExts
{
public static IEnumerable<string> ReverseCut(this string txt, int cutSize)
{
int first = txt.Length % cutSize;
int taken = 0;
string nextResult = new String(txt.Take(first).ToArray());
taken += first;
do
{
if (nextResult.Length > 0)
yield return nextResult;
nextResult = new String(txt.Skip(taken).Take(cutSize).ToArray());
taken += cutSize;
} while (nextResult.Length == cutSize);
}
}
}
Usage:
textBox2.Text = "";
var txt = textBox1.Text;
foreach (string s in txt.ReverseCut(3))
textBox2.Text += s + "\r\n";
Regex time!!
Regex rx = new Regex("^(.{1,2})??(.{3})*$");
var matches = rx.Matches("abcdefgh");
var pieces = matches[0].Groups[1].Captures.OfType<Capture>().Select(p => p.Value).Concat(matches[0].Groups[2].Captures.OfType<Capture>().Select(p => p.Value)).ToArray();
pieces will contain:
"ab"
"cde"
"fgh"
(Please, don't use this code! It is only an example of what can happen when you use a regular expression + LINQ.)
Well... here is yet another way I arrived at:
private string[] splitIntoAry(string str)
{
string[] temp = new string[(int)Math.Ceiling((double)str.Length / 3)];
while (str != string.Empty)
{
temp[(int)Math.Ceiling((double)str.Length / 3) - 1] = str.Substring(str.Length - Math.Min(str.Length, 3));
str = str.Substring(0, str.Length - Math.Min(str.Length, 3));
}
return temp;
}

Categories