I have multiple TXT files which represents time spans in seconds for selected portions of videos. For example, 1.23-5.45.
I want to use these time spans to take these portions of multiple videos and create a single video with all the portions.
I'm parsing all of these TXT files into an array of KeyValue pairs list:
List<KeyValuePair<Double, Double>>[] TagsOfSeconds= new List<KeyValuePair<Double, Double>>[]()
Each index of array element represents a TXT file. And each element is a a KeyValue pair list where each pair is the start-end of the seconds time span.
My requirement is to parse these TXT files and split the time spans to segments of 5 seconds (5 is an example, the segment value will be provided by the user) and order the segments with priority to segment with the smallest value (happened before other segments) and if two are equal, take the one that is first in the TagsOfSeconds array.
Here is an illustration. Segment order is what I'm trying to achieve:
I created the following structure to keep track of the portions parsed from the text files:
public struct PortionInfo
{
public Double Start, End;
public int VideoIndex, PortionIndex;
public Double PortionLength;
}
Here is my code for ordering the loaded segments based on the start time span and TXT file index:
private void OrderVideoPortions(List<KeyValuePair<Double, Double>>[] videoPortionslist)
{
videoPortionsOrder = new List<PortionInfo>(); //videoPortionsOrder.Sort()
for(int i=0;i< videoPortionslist.Length;i++)
{
for (int j = 0; j < videoPortionslist[i].Count; j++)
{
PortionInfo currentPortionInfo = new PortionInfo();
currentPortionInfo.VideoIndex = i;
currentPortionInfo.PortionIndex = j;
currentPortionInfo.Start = videoPortionslist[i][j].Key;
currentPortionInfo.End = videoPortionslist[i][j].Value;
currentPortionInfo.PortionLength = currentPortionInfo.End - currentPortionInfo.Start;
videoPortionsOrder.Add(currentPortionInfo);
}
}
videoPortionsOrder.Sort(SortAscending);
}
public static int SortAscending(PortionInfo p1, PortionInfo p2)
{
int returnVal = p1.Start.CompareTo(p2.Start);
if (returnVal == 0)
{
return p1.VideoIndex.CompareTo(p2.VideoIndex);
}
else
return returnVal;
}
Now I have to generate the segments from the sorted list.
Can any one help me please to achieve this? I just want help or guidance on determining the intersections and segments.
I modified the PortionInfo Structure to have constructor and a bool Active that is set automatically to true when the structure is created.
private void CreateFinalSegments(List<PortionInfo> orderedVideoPortions)
{
int segmentSize = int.Parse(_txtTimeSegments.Text);
int extrSegmentDuration = int.Parse(_txtExtraDurationAllowed.Text);
PortionInfo currentPortion = new PortionInfo();
finalSegments = new List<PortionInfo>();
if (_txtExtraDurationAllowed.Text == "0" || _txtTimeSegments.Text == "0")
{
return;//Check that still needs to be handled
}
else
{
for (int i=0;i< orderedVideoPortions.Count;i++)
{
if (orderedVideoPortions[i].Active)
{
if (orderedVideoPortions[i].PortionLength <= (segmentSize + extrSegmentDuration))
{
finalSegments.Add(orderedVideoPortions[i]);
currentPortion = orderedVideoPortions[i];
currentPortion.Active = false;
orderedVideoPortions[i]=currentPortion ;
}
else
{
currentPortion = orderedVideoPortions[i];
finalSegments.Add(new PortionInfo(currentPortion.Start, currentPortion.Start+ segmentSize, currentPortion.VideoIndex, currentPortion.PortionIndex));
currentPortion.Start += segmentSize;
currentPortion.PortionLength = currentPortion.End - currentPortion.Start;
orderedVideoPortions[i] = currentPortion;
orderedVideoPortions.Sort(SortAscending);
i = 0;//Note: Needs to be rechecked because --i should be enough.
}
}
}
Application.DoEvents();
_lblStatus.Text = "Video segments generated. Now Working on generating final video";
}
}
Related
I am trying to join the next array element together to single element from array if the element of the array is less than length 4. It should add to the next element index.
Another logic is, if the next consecutive array length is also less then 4 char then it joins the next array element also up to 3 times in total. I want to implement this. It's getting complex for me I am not understand this logic.
This is the code, here it has array on titleList, now we have to use the above logic in this array list.
#foreach (var title in randomtitle)
{
</span>#titleList.ElementAt(title)</span>
}
#code {
[Parameter]
public string theTitle { get; set; }
private string[] titleList = Array.Empty<string>();
protected override void OnParametersSet()
{
if (!string.IsNullOrEmpty(theTitle))
{
titleList = theTitle.Split(" ");
}
}
private Random random = new();
private IEnumerable<int> randomtitle =>
Enumerable.Range(0, titleList.Count() - 1) // { 0, 1, 2, 3 } generate sequence
.OrderBy(x => random.Next()) // { 3, 1, 0, 2 } random shuffle
.Take(2) // { 3, 1 } pick two
.ToList();
}
I think you are looking for a method that does following:
take a collection of strings(like a string[])
iterate each string and check if it's length is greater than or equal 4
if so, everything is fine, take it as it is
if not, append the next to the current string and check their length afterwards
if they are still not greater than or equal 4 append the next one, but max 3 times
Then this should work (not tested well though):
Demo: https://dotnetfiddle.net/2uHREv
static string[] MergeItems(IList<string> all, int minLength, int maxGroupCount)
{
List<string> list = new List<string>(all.Count);
for(int i = 0; i < all.Count; i++)
{
string current = all[i];
if(i == all.Count - 1)
{
list.Add(current);
break;
}
if (current.Length < minLength)
{
for (int ii = 1; ii < maxGroupCount && i + ii < all.Count; ii++)
{
int nextIndex = i + ii;
string next = all[nextIndex];
current = current + next;
if (current.Length >= minLength || ii+1 == maxGroupCount)
{
list.Add(current);
i = nextIndex;
break;
}
}
}
else
{
list.Add(current);
}
}
return list.ToArray();
}
Hi guys i am reading a file containing playlists.
(Rows of mp3 file locations)
I currently have the format ( name ; c:\song.mp3 ; c:\song.mp3 ; c:\song.mp3 ; c:\song.mp3 etc etc)
There are many rows of these in the file.
I have tried both foreach loops and for loops to try and solve this (as shown below)
string[] lines = File.ReadAllLines("playlists.txt");
MessageBox.Show(lines.Count().ToString());
for (int y = 0; y <= lines.Count(); y++)
{
string[] res = lines[y].Split(';');
for (int x = 0; x <= res.Count(); x ++)
{
if (x == 0) { currentPlaylist = new Playlist(res[x]); }
else { currentPlaylist.Add(new MP3(res[x])); }
}
}
But for some reason it will only loop once (I have replaced the outer loop with a foreach which had the same result.
even if the lines.Count() shown in the messagebox shows a number greater then 1
I'm sure once this is solved it must be basic mistake but Im lost
Thanks
EDIT* this is the file dont know how this will help...
Library;C:\Users\Blah\Desktop\Iphone Music\Queens of the Stone Age - If I Had A Tail.mp3
playlist1;C:\Users\Blah\Desktop\Iphone Music\Red Hot Chili Peppers - Can t Stop.mp3;C:\Users\Blah\Desktop\Iphone Music\Red Hot Chili Peppers - Otherside .mp3
playlist2;C:\Users\Blah\Desktop\Iphone Music\Red Hot Chili Peppers - Otherside .mp3;C:\Users\Blah\Desktop\Iphone Music\Foo Fighters - Best Of You.mp3
playlist3;C:\Users\Blah\Desktop\Iphone Music\Red Hot Chili Peppers - Otherside.mp3;C:\Users\Blah\Desktop\Iphone Music\Foo Fighters - The Pretender.mp3
playlist4;C:\Users\Blah\Desktop\Iphone Music\Foo Fighters - Everlong.mp3;C:\Users\Blah\Desktop\Iphone Music\Foo Fighters - My Hero.mp3;C:\Users\Blah\Desktop\Iphone Music\I Am Giant - City Limits.mp3
I put it in as code so it would be easier to read
The only issue i am having is that the inner loop only fires once and i am unsure as to why.
Something in the following ....
for (int x = 0; x <= res.Count(); x ++)
{
if (x == 0) { currentPlaylist = new Playlist(res[x]); }
else { currentPlaylist.Add(new MP3(res[x])); }
}
is causing the outer loop to only fire once no matter the amount of lines in the code, if i remove the inner loop the outer loop loops the expected amount of times
Based on your question and comments you wrote, I think you are looking for something like:
// This method read the file and populate a List of Playlist.
// Each PlayList contain a list of MP3 songs
public List<Playlist> GetPlayLists()
{
// read all lines from the text file
string[] lines = File.ReadAllLines(#"c:\Temp\playlists.txt");
// declare a playlists variable to hold all the playlists and their songs
var playlists = new List<Playlist>();
// Loop through all the playlists (each line in the text file represents a playlist)
for (int plIdx = 0; plIdx < lines.Length; plIdx++)
{
// split in order to fins all the MP3 songs
string[] res = lines[plIdx].Split(';');
// create a new playlist (its name is passed into the constructor)
var playlist = new Playlist(res[0]);
// loop the songs (starting from index 1 since index=0 is the playlist name)
for (int songIdx = 1; songIdx < res.Length; songIdx++)
{
// Add to the playlist each song
playlist.Add(new MP3(res[songIdx]));
}
playlists.Add(playlist);
}
return playlists;
}
// Play list class containing all the MP3 songs (each line in text file)
class Playlist
{
public List<MP3> SongList { get; private set; }
public string Name { get; private set; }
public Playlist(string name)
{
Name = name;
SongList = new List<MP3>();
}
public void Add(MP3 mp3)
{
SongList.Add(mp3);
}
}
// MP3 Song class
class MP3
{
public string Location { get; private set; }
public MP3(string location)
{
Location = location;
}
}
This is how your playlists variable looks like after it has been populated with your playlists.txt file:
Do the following steps in order to make it work. Once working, you will have a reference so you can simply merge it into your existing project.
Create a new Console Application
Your class program:
class Program
{
static void Main(string[] args)
{
// FileReader is the class that contains the method that read from the playlists.txt file
var filereader = new FileReader();
var playlists = filereader.GetPlayLists();
}
}
Create a FileReader class and put the GetPlayLists method into
class FileReader
{
// This method read the file and populate a List of Playlist.
// Each PlayList contain a list of MP3 songs
public List<Playlist> GetPlayLists()
{
// .....
}
}
Put the other classes PlayList and MP3.
Now you should be able to run it without any issues.
Your code should throw an exception, as far as I can see. You use <= in your loop conditions, but when x == res.Count() you can not access res[x], because the index must be between 0 and Count-1.
Try to replace <= by <, at least.
And don't use Count() on arrays. They have .Length property.
Assuming that what you posted is the file you're reading then each line contains a single file location of the mp3. After splitting each line with ';' you can safely assume that the 2nd entry of the new array is the file path.
string[] lines = File.ReadAllLines("playlists.txt"); // 100 lines
for (int y = 0; y < lines.Length; y++) loops through array index 0 to 99
{
string[] res = lines[y].Split(';'); // lines[y] should be something like c:\song.mp3 ; c:\song.mp3 ; c:\song.mp3
// res[0] = Library
// res[1] = C:\Users\Blah\Desktop\Iphone Music\Queens of the Stone Age - If I Had A Tail.mp3
currentPlaylist = new Playlist(res[0].Trim());
currentPlaylist.Add(new MP3(res[1].Trim()));
}
Or if each line has multiple file paths..
string[] lines = File.ReadAllLines("playlists.txt"); // 100 lines
for (int y = 0; y < lines.Length; y++) loops through array index 0 to 99
{
string[] res = lines[y].Split(';'); // lines[y] should be something like c:\song.mp3 ; c:\song.mp3 ; c:\song.mp3
// res[0] = Library
// res[1] = C:\Users\Blah\Desktop\Iphone Music\Queens of the Stone Age - If I Had A Tail.mp3
currentPlaylist = new Playlist(res[0].Trim()); // res[0] is the playlist name right?
for(int x = 1; x < res.Length; x++)
{
currentPlaylist.Add(new MP3(res[x].Trim()));
}
}
Try this, you should not initialise currentPlayList in the inner loop as it will get reinitialised every time it loops through y
Playlist currentPlaylist;
string[] lines = File.ReadAllLines("playlists.txt");
for (int y = 0; y < lines.Length; y++)
{
if (y == 0) {
currentPlaylist = new Playlist();
}
string[] res = lines[y].Split(';');
for (int x = 0; x < res.Length; x ++)
{
currentPlaylist.Add(new MP3(res[x]));
}
}
Your outer loop actually runs more than once, but because you reinitialise the playlist, the only state that is persisted at the end of the outer loop is the very last iteration, this giving the appearance of having run only once.
this is my very first post here on StackOverflow so please tell me if I did anything wrong, also english is not my native language, forgive me if there is any gramatical errors.
My question is how can I permutate the items of an array of type "Location", I need to get all possible permutations of waypoints given by the user to then calculate the best route based on time or distance. (I don't want to use the normal route calculation)
I've searched for algorithms but all of them when I put the array of type "Location[]" in the function's parameter I get the error that the object needs to be IEnumerable and I don't know how to convert to that if is even possible, I never worked with IEnumerable.
If it is of any help this is my code for calculating the route:
//Gets the waypoints from a listBox provided by the user, "mode" selects between best time and best distance
//backgroundworker so the UI dont freezes, and return the optimal waypoint order
public Location[] CalcularRota(Location[] waypoints, int mode, BackgroundWorker work, DoWorkEventArgs e)
{
//Declarations
string origem = "";
string destino = "";
Rota[] prop = new Rota[100]; //this index is the number of times the algorithm will be executed, more equals accuracy but much more time to complete
Rota bestDist = new Rota();
Rota bestTime = new Rota();
DirectionService serv = new DirectionService();
DirectionRequest reqs = new DirectionRequest();
DirectionResponse resp;
Random rnd = new Random();
Location[] rndWays;
int dist = 0;
int ti = 0;
bestDist.Distance = 1000000000; //put higher values for the first comparation to be true (end of code)
bestTime.Time = 1000000000;
if (waypoints != null)
{
reqs.Sensor = false;
reqs.Mode = TravelMode.driving;
for (int i = 0; i < prop.Length; i++) //initializes prop
prop[i] = new Rota();
for (int i = 0; i < prop.Length; i++)
{
rndWays = waypoints.OrderBy(x => rnd.Next()).ToArray(); //randomizes the order, I want to get all permutations and then test
//but I dont know how so I've been using randomized
dist = ti = 0;
origem = prop[0].ToString(); //save this particular waypoint's origin and destination
destino = prop[1].ToString();
reqs.Origin = origem;
reqs.Destination = destino;
if (waypoints.Length > 0)
reqs.Waypoints = rndWays;
resp = serv.GetResponse(reqs); //request the route with X order of waypoints to google
if (resp.Status == ServiceResponseStatus.Ok) //wait the response otherwise the program crashes
{
for (int j = 0; j < resp.Routes[0].Legs.Length; j++) //gets the distance and time of this particular order
{
ti += int.Parse(resp.Routes[0].Legs[j].Duration.Value);
dist += int.Parse(resp.Routes[0].Legs[j].Distance.Value);
}
}
prop[i].Origem = origem; //saves this waypoints order details for further comparison
prop[i].Destino = destino;
prop[i].Distance = dist;
prop[i].Time = ti;
prop[i].Order = rndWays;
work.ReportProgress(i); //report the progress
}
for (int i = 0; i < prop.Length; i++) //gets the best distance and time
{
if (bestDist.Distance > prop[i].Distance)
{
bestDist.Distance = prop[i].Distance;
bestDist.Time = prop[i].Time;
bestDist.Order = prop[i].Order;
bestDist.Origem = prop[i].Origem;
bestDist.Destino = prop[i].Destino;
}
if (bestTime.Time > prop[i].Time)
{
bestTime.Distance = prop[i].Distance;
bestTime.Time = prop[i].Time;
bestTime.Order = prop[i].Order;
bestTime.Origem = prop[i].Origem;
bestTime.Destino = prop[i].Destino;
}
}
if (bestDist.Order == bestTime.Order) //if the same waypoint order has the same time and distance
return bestDist.Order; // returns whatever bestDist.Order or bestTime.Order
else if (bestDist.Order != bestTime.Order) //if different returns corresponding to the mode selected
{
if (mode == 1) return bestDist.Order;
if (mode == 2) return bestTime.Order;
}
}
return null;
}
What I want is to permutate the waypoints given and test each permutation, I've been struggling with this for a time, if u guys could help me with any way possible would be great.
Ty.
EDIT.
I found this function here on StackOverflow:
public static bool NextPermutation<T>(T[] elements) where T : IComparable<T>
{
var count = elements.Length;
var done = true;
for (var i = count - 1; i > 0; i--)
{
var curr = elements[i];
// Check if the current element is less than the one before it
if (curr.CompareTo(elements[i - 1]) < 0)
{
continue;
}
// An element bigger than the one before it has been found,
// so this isn't the last lexicographic permutation.
done = false;
// Save the previous (bigger) element in a variable for more efficiency.
var prev = elements[i - 1];
// Have a variable to hold the index of the element to swap
// with the previous element (the to-swap element would be
// the smallest element that comes after the previous element
// and is bigger than the previous element), initializing it
// as the current index of the current item (curr).
var currIndex = i;
// Go through the array from the element after the current one to last
for (var j = i + 1; j < count; j++)
{
// Save into variable for more efficiency
var tmp = elements[j];
// Check if tmp suits the "next swap" conditions:
// Smallest, but bigger than the "prev" element
if (tmp.CompareTo(curr) < 0 && tmp.CompareTo(prev) > 0)
{
curr = tmp;
currIndex = j;
}
}
// Swap the "prev" with the new "curr" (the swap-with element)
elements[currIndex] = prev;
elements[i - 1] = curr;
// Reverse the order of the tail, in order to reset it's lexicographic order
for (var j = count - 1; j > i; j--, i++)
{
var tmp = elements[j];
elements[j] = elements[i];
elements[i] = tmp;
}
// Break since we have got the next permutation
// The reason to have all the logic inside the loop is
// to prevent the need of an extra variable indicating "i" when
// the next needed swap is found (moving "i" outside the loop is a
// bad practice, and isn't very readable, so I preferred not doing
// that as well).
break;
}
// Return whether this has been the last lexicographic permutation.
return done;
}
The usage is:
NextPermutation(array);
Doing this and putting my array (rndWays) as overload I get the following error:
The type 'Google.Maps.Location' cannot be used as type parameter 'T' in the generic type or method 'Form1.NextPermutation< T >(T[])'. There is no implicit reference conversion from 'Google.Maps.Location' to 'System.IComparable< Google.Maps.Location >'.
The problem is that Location does not implement the IComparable interface.
Change:
public static bool NextPermutation<T>(T[] elements) where T : IComparable<T>
to:
public static bool NextPermutation(Location[] elements)
And replace each CompareTo() with your own comparison function.
For a school project in learning c# I am making a data collection console application which saves floating point entries for 4 different locations along with the time/date, and user who recorded the entry. I am required to use a multi dimensional struct array.
I need to have a view that displays the average of the values, along with the minimum and maximum values and the first and last date. I've got the average figured out by counting through the values and adding cumulatively but I can't figure out how to find the minimum and maximum values.
I tried searching and came across this page: http://www.dotnetperls.com/max
I tried to implement this syntax into my code to no avail due to it being a much more complex array.
It worked in my test with integers:
class Program
{
static int[][] intarray = new int[4][] { new int[10], new int[10], new int[10], new int[10] };
static void Main(string[] args)
{
intarray[0][0] = 5;
intarray[0][1] = 3;
intarray[0][2] = 10;
intarray[0][3] = 4;
intarray[0][4] = 2;
Console.WriteLine(intarray[0].Max());
Console.ReadLine();
}
}
The above code perfectly displays the number 10! :)
But when I tried to implement this in to my program with a struct array, it doesn't work:
class Program
{
static byte location = 0;
static float entriesmin;
static float entriesmax;
static Entry[][] entriesarray = new Entry[4][] { new Entry[10], new Entry[10], new Entry[10], new Entry[10] };
struct Entry
{
public float value;
public string user;
public DateTime datetime;
}
static byte LoopEntries(bool display)
{
float runningtotal = 0;
byte entrycount = 0;
foreach (Entry entry in entriesarray[0])
{
if (entry.user != null)
{
if (display)
{
string ten;
if (entrycount == 9)
{
ten = " #";
}
else
{
ten = " #";
}
Console.WriteLine(ten + (entrycount + 1) + " " + entry.datetime + " " + entry.user + new string(' ', 16 - entry.user.Length) + entry.value);
}
runningtotal += entry.value;
entrycount += 1;
}
}
entriesmin = (entriesarray[location]).value.Min();
entriesmax = (entriesarray[location]).value.Max();
if (entrycount == 0 && display)
{
Console.WriteLine("No entries to show!");
}
return entrycount;
}
I need to hand this project in on Monday! I really hope someone can help me! ;)
What you have is not a multidimensional array, it's an array of array (a.k.a. a jagged array), but you work with them in a similar way.
To loop through the array of arrays you need a loop in a loop:
foreach (Entry[] arr in entriesarray) {
foreach (Entry entry in arr) {
// ...
}
}
You could use the Min and Max extension methods to get the minimum and maximum value of each inner array, but you still would have to find the minimum and maximum between those values. As you are already looping through all the entries anyway to get the average you can just keep a record of the smallest and largest values found:
float runningtotal = 0;
int entrycount = 0;
float min = float.MaxValue;
float max = float.MinValue;
foreach (Entry[] arr in entriesarray) {
foreach (Entry entry in arr) {
runningtotal += entry.value;
entrycount++;
if (entry.value < min) {
min = entry.value;
}
if (entry.value > max) {
max = entry.value;
}
}
}
I want to publish server-messages on Twitter, for our clients.
Unfortunately, Twitter only allows posting 140 Chars or less. This is a shame.
Now, I have to write an algorithm that concatenates the different messages from the server together, but shortens them to a max of 140 characters.
It's pretty tricky.
CODE
static string concatinateStringsWithLength(string[] strings, int length, string separator) {
// This is the maximum number of chars for the strings
// We have to subtract the separators
int maxLengthOfAllStrings = length - ((strings.Length - 1) * separator.Length);
// Here we save all shortenedStrings
string[] cutStrings = new string[strings.Length];
// This is the average length of all the strings
int averageStringLenght = maxLengthOfAllStrings / strings.Length;
// Now we check how many strings are longer than the average string
int longerStrings = 0;
foreach (string singleString in strings)
{
if (singleString.Length > averageStringLenght)
{
longerStrings++;
}
}
// If a string is smaller than the average string, we can more characters to the longer strings
int maxStringLength = averageStringLenght;
foreach (string singleString in strings)
{
if (averageStringLenght > singleString.Length)
{
maxStringLength += (int)((averageStringLenght - singleString.Length) * (1.0 / longerStrings));
}
}
// Finally we shorten the strings and save them to the array
int i = 0;
foreach (string singleString in strings)
{
string shortenedString = singleString;
if (singleString.Length > maxStringLength)
{
shortenedString = singleString.Remove(maxStringLength);
}
cutStrings[i] = shortenedString;
i++;
}
return String.Join(separator, cutStrings);
}
Problem with this
This algorithm works, but it's not very optimized.
It uses less characters than it actually could.
The main problem with this is that the variable longerStrings is relative to the maxStringLength, and backwards.
This means if I change longerStrings, maxStringLength gets changed, and so on and so on.
I'd have to make a while loop and do this until there are no changes, but I don't think that's necessary for such a simple case.
Can you give me a clue on how to continue?
Or maybe there already exists something similar?
Thanks!
EDIT
The messages I get from the server look like this:
Message
Subject
Date
Body
Message
Subject
Date
Body
And so on.
What I want is to concatenate the strings with a separator, in this case a semi-colon.
There should be a max length. The long strings should be shortened first.
Example
This is a subject
This is the body and is a bit lon...
25.02.2013
This is a s...
This is the...
25.02.2013
I think you get the idea ;)
Five times slower than yours (in our simple example) but should use maximum avaliable space (no critical values checking):
static string Concatenate(string[] strings, int maxLength, string separator)
{
var totalLength = strings.Sum(s => s.Length);
var requiredLength = totalLength - (strings.Length - 1)*separator.Length;
// Return if there is enough place.
if (requiredLength <= maxLength)
return String.Concat(strings.Take(strings.Length - 1).Select(s => s + separator).Concat(new[] {strings.Last()}));
// The problem...
var helpers = new ConcatenateInternal[strings.Length];
for (var i = 0; i < helpers.Length; i++)
helpers[i] = new ConcatenateInternal(strings[i].Length);
var avaliableLength = maxLength - (strings.Length - 1)*separator.Length;
var charsInserted = 0;
var currentIndex = 0;
while (charsInserted != avaliableLength)
{
for (var i = 0; i < strings.Length; i++)
{
if (charsInserted == avaliableLength)
break;
if (currentIndex >= strings[i].Length)
{
helpers[i].Finished = true;
continue;
}
helpers[i].StringBuilder.Append(strings[i][currentIndex]);
charsInserted++;
}
currentIndex++;
}
var unified = new StringBuilder(avaliableLength);
for (var i = 0; i < strings.Length; i++)
{
if (!helpers[i].Finished)
{
unified.Append(helpers[i].StringBuilder.ToString(0, helpers[i].StringBuilder.Length - 3));
unified.Append("...");
}
else
{
unified.Append(helpers[i].StringBuilder.ToString());
}
if (i < strings.Length - 1)
{
unified.Append(separator);
}
}
return unified.ToString();
}
And ConcatenateInternal:
class ConcatenateInternal
{
public StringBuilder StringBuilder { get; private set; }
public bool Finished { get; set; }
public ConcatenateInternal(int capacity)
{
StringBuilder = new StringBuilder(capacity);
}
}