how to skip a few iterations in a loop in Ruby? - ruby

Suppose I have the C code below
for(i = 0; i < 10; i++){
printf("Hello");
if(i == 5){
a[3] = a[2] * 2;
if(a[3] == b)
i = a[3]; //Skip to index = a[3]; depends on runtime value
}
}
How to convert to Ruby? I know we can skip one iteration using next, but I have to skip a few iterations depending on conditional value and I don't know how many iterations to skip before runtime?
Here is the code I am actually working on (as mentioned by Coreyward):
I am looking for "straight line" in the array that the values differs less than 0.1(less than 0.1 will considered as a "straight line"). The range has to be longer than 50 to be considered as a long "line". After I find the line range [a,b], i wanna skip the iterations to upper limit b so it would not start again from a+1, and it will start to find new "straight line" from b+1
for(i=0; i<arr.Length; i++){
if(arr[i] - arr[i + 50] < 0.1){
m = i; //m is the starting point
for(j=i; j<arr.Length; j++){ //this loop makes sure all values differs less than 0.1
if(arr[i] - arr[j] < 0.1){
n = j;
}else{
break;
}
}
if(n - m > 50){ //Found a line with range greater than 50, and store the starting point to line array
line[i] = m
}
i = n //Start new search from n
}
}

Your case isn't easily covered by typical ruby iterators, but ruby also has ordinary while loops which can completely cover c-for. the following is equivalent to your c for loop above.
i = 0;
while i < 10
puts "Hello"
if i == 5
a[3] = a[2] * 2
i = a[3] if a[3] == b
end
# in your code above, the for increment i++ will execute after assigning new i,
# though the comment "Skip to index = a[3]" indicates that may not be your intent
i += 1
end

Another way is using the enumerator class:
iter = (1..10).to_enum
while true
value = iter.next
puts "value is #{value.inspect}"
if value == 5
3.times {value = iter.next}
end
end
gives
value is 1
value is 2
value is 3
value is 4
value is 5
value is 9
value is 10
StopIteration: iteration reached at end
from (irb):15:in `next'
from (irb):15
from C:/Ruby19/bin/irb:12:in `<main>'

Related

is this loop invariant and post condition correct?

I was trying to write a loop invariant and post condition for this code:
sum = 0;
for (i = 0; i < 10; ++i)
++sum;
sum = 10 is the obvious post condition here. But a friend told me that i = sum is also a loop invariant and sum = 12 is also a post condition. I checked the following:
loop invariant is initially true: that's true for i = sum since both are 0 initially
loop invariant is preserved: assume i < 10 and i = sum then after one iteration it's still true that ++i = ++sum
loop invariant implies post condition: assume i >= 10 and i = sum then sum = 12 is also true
But obviously sum doesn't equal to 12 here. So what's wrong with my reasoning here?
Take a slightly different invariant i == sum && i <= 10. Together with i >= 10 you get then i = sum = 10.
Btw. in your original reasoning you cannot conclude that sum = 12 is true but only that sum >= 10. The latter is correct, just not strong enough to prove the desired result.
// Loop invariant SUM_IS_INDEX: sum == i
// Loop variant: i is increased in every step, and initial value 0 before 10.
sum = 0;
for (i = 0;
// SUM_IS_INDEX before the actual loop
i < 10;
// next loop step, after first step:
// sum == index + 1
++i
// next index = index + 1
// sum == index
// SUM_IS_INDEX after a loop step, continuing
) {
// SUM_IS_INDEX
++sum;
// sum == index + 1
}
// Post: i >= 10 (negation of the for condition), SUM_IS_INDEX
The comment about 12 relates more to i. To have i == 10 one would need to add a predicate on increments of just 1.
Best practise is to rewrite the for in control flow order:
sum = 0;
i = 0;
while (i < 10)
++sum;
++i:
}
This prevents silly mistakes.

LSD Radix Sort for Integers

I'm having trouble wrapping my head around using radix sort for a group of fixed-length integers. In my below attempt to implement least significant digit radix sort, I have a function called num_at which returns the digit d in the number num. The code I've written has w = 2, where w represents the length of each number. (Essentially, then, this code is written for 3 digit numbers as my input below shows).
I modeled this off of key-indexed counting for each digit, but I'm getting an output of [0, 12, 32, 32, 44, 0] and frankly having a tough time following why. This is my input: [32,12,99,44,77, 12] I initiated the count array with 99 values because of all the possible values there can be between 0 - 99 in accordance with key indexed counting. Does anything here immediately jump out as incorrect? Also, is my num_at method the right way to do this or is there a better way?
def num_at(num, d)
return num if num/10 == 0
a = num
#return the dth digit of num
counter = 0
until counter == d
a/=10
counter += 1
end
a % 10
end
def radix_sort(arr)
w = 2
#count_arr can have any possible number from 0-99
aux = Array.new(arr.length) {0}
d = w-1
while d >= 0
count = Array.new(99) {0}
i = 0
#create freq arr
while i < arr.length
count[num_at(arr[i], d) + 1] += 1 #offset by 1
i += 1
end
#compute cumulates
i = 0
while i < count.length - 1
count[i + 1] += count[i]
i += 1
end
z = 0
#populate aux arr
while z < arr.length
aux[num_at(arr[z], d)] = arr[z]
count[num_at(arr[z], d)] += 1
z += 1
end
#override original arr
z = 0
while z < arr.length
arr[z] = aux[z]
z += 1
end
d -= 1
end
arr
end
This is functioning Java code for LSD radix sort taken from a textbook that I'm trying to implement with Ruby:
public static void lsd(String[] a)
{
int N = a.length;
int W = a[0].length;
for (int d = W-1; d >= 0; d--)
{
int[] count = new int[R];
for (int i = 0; i < N; i++)
count[a[i].charAt(d) + 1]++;
for (int k = 1; k < 256; k++)
count[k] += count[k-1];
for (int i = 0; i < N; i++)
temp[count[a[i].charAt(d)]++] = a[i];
for (int i = 0; i < N; i++)
a[i] = temp[i];
}
and the pseudocode for key-indexed counting (which is being repeated for every char):
Task: sort an array a[] of N integers between 0 and R-1
Plan: produce sorted result in array temp[]
1. Count frequencies of each letter using key as index
2. Compute frequency cumulates
3. Access cumulates using key as index to find record positions.
4. Copy back into original array
5. List item
LSD radix sort. Consider characters d from right to left Stably sort
using dth character as the key via key-indexed counting.
The above java code / pseudocode information is pulled from this link: http://www.cs.princeton.edu/courses/archive/spring07/cos226/lectures/11RadixSort.pdf

Determine if a sorted array contains a contiguous sequence that sums up to N

I'm trying to write an algorithm that will return True/False whether a contiguous sequence in a sorted array that contains only positive integers, can sum up to N.
For example:
Array = { 1, 2, 3, 4 };
6 is good! 1 + 2 + 3 = 6
8 is not good! 1 + 3 + 4 = 8, but it's not contiguous, since we skipped the 2.
This is what I have tried to do:
int[] arr = ...;
int headIndex = 1, tailIndex = 0, sum = arr[0];
while (sum != n)
{
if (sum < n)
{
sum += arr[headIndex++];
}
if (sum > n)
{
sum -= arr[tailIndex++];
}
}
return sum == n;
Obviously the above does not work (In some cases it might get stuck in an infinite loop). Any suggestions?
One thing I haven't mentioned earlier, and is very important- the algorithm's complexity must be low as possible.
This is just a sketch:
Loop from left to right, find the largest k that n1 + ... + nk <= target, set sum = n1 + ... + nk. If the array sum is smaller than target, then return false.
If sum == target, we are done. If not, then any subarray S that sum to target will have S.length < k, and will begin from an element that is larger than the first one. So we kick out the first from the sum: sum -= n1, leftEnd++. Now we can go back to step 1, but no need to compute k from scratch.
Since the left end moves at most N times, and the right end moves at most N times, this algorithm has time complexity O(N), and constant space requirement.
var i = 0;
while(i != arr.Length)
{
var remembre = i;
var tmp = 0;
for(; tmp < N && i < arr.Length; ++i)
tmp += arr[i];
if(N == tmp)
return true;
i = remembre + 1;
}
return false;
I believe this should work.
Simply:
for i = 1 to n - 1:
j = 0
while (j < i):
sm = 0
for k = j to i:
sm = sm + array[k]
if sm == N:
return True
j = j + 1
return False
This works in O(n^3) time.
Here is a solution in code. It's been heavily influenced by #Ziyao Wei's sketch, which simplified my original approach (in particular, there is no need to backtrack and add the small numbers back on, only to take them off as I first thought).
public static bool HasConsecutiveSum(IList<int> list, int requiredSum)
{
int start = 0;
int sum = 0;
for (int end = 0; end < list.Count; end++)
{
sum += list[end];
while (sum > requiredSum)
{
sum -= list[start++];
if (start > end)
{
return false;
}
}
if (sum == requiredSum)
{
return true;
}
}
return false;
}
I think the most optimal algorithm works with a window that moves over the list. The value of the window (WV) is the sum of the elements that fall within the window. If WV is less then N, move the head and add the new value that fits within the window to WV, if the value is bigger then N, move the tail one up and subtract the value that falls of the window from WV. The algorithm stops when WV equals N, or the tail moves beyond the head, or the head is at the end of the list, and WV is still to low.
This would run in linear time: every element in the list is once added and once subtracted at most.
Written down in some code to illustrate the idea (python alike), but not tested
WV = list[0]
L = len(list)
tail = 0
head = 0
while WV != N
if WV < N
head += 1
if head < L
WV += list[head]
else
return false // beyond end of list
elif WV > N
if tail < head
WV -= list[tail]
tail += 1
else
return false // single element bigger then N, and list is sorted
return true

Insertion sort in Ruby [duplicate]

This question already has answers here:
Learning Insertion Sort in Ruby
(6 answers)
Closed 5 years ago.
Here is the algorithm of insertion sort in C++ (from tutorial):
void insertionSort(int arr[], int length) {
int i, j, tmp;
for (i = 1; i < length; i++) {
j = i;
while (j > 0 && arr[j - 1] > arr[j]) {
tmp = arr[j];
arr[j] = arr[j - 1];
arr[j - 1] = tmp;
j--;
}
}
}
and here is what I'm doing in Ruby
a = [12, 1, 18, -3, -2, 66, 31]
puts a
def insertion_sort(source)
source.to_enum.with_index(1).each do |item, i|
j = i
while((j>0) && (source[j-1] > source[j]))
source[j], source[j-1] = source[j-1], source[j]
j -= 1
end
end
end
insertion_sort(a)
puts a
it throws an error of comparison of Fixnum with nil failed (ArgumentError). Probably because of overflow.
What did I do wrong?
In the C++ version you have (i = 1; i < length; i++). Which means, it will not run the last round where i = length. That would be out of the array.
In ruby, because you set the offset of the index to 1, the last round, you would have i = length. Hence source[length] is out of source, so returns nil.
1 > nil # source[j-1] > source[j] when j = length
# ArgumentError: comparison of Fixnum with nil failed
While #oldergod already answer your question, I just wanna add some fix to the problem.
Here sample of code taken from algorithm gem
def insertion_sort(container)
return container if container.size < 2
(1..container.size-1).each do |i|
value = container[i]
j = i-1
while j >= 0 and container[j] > value do
container[j+1] = container[j]
j = j-1
end
container[j+1] = value
end
container
end
Here you iterate over a number, 1, the second index of the container, to container.size - 1, the last index.

Word wrap to X lines instead of maximum width (Least raggedness)

Does anyone know a good algorithm to word wrap an input string to a specified number of lines rather than a set width. Basically to achieve the minimum width for X lines.
e.g. "I would like to be wrapped into two lines"
goes to
"I would like to be
wrapped into two lines"
"I would like to be wrapped into three lines"
goes to
"I would like to
be wrapped into
three lines"
Inserting new lines as required. I can find other word wrap questions but they all have a known width and want to insert as many lines as needed to fit that width. I am after the opposite.
Answers preferable in a .NET language but any language would be helpful. Obviously if there is a framework way to do this I am not aware of let me know.
Edit I have found this since which I think the accepted answer is the solution to my problem but am having difficulty understanding it. Algorithm to divide text into 3 evenly-sized groups any chance someone could convert it to c# or vb.net.
A way of solvng this problem would be using dynamic programming, You can solve this problem using dynamic programming, cf Minimum raggedness algorithm.
I used some of the informations you add when you eddited your post with :
Algorithm to divide text into 3 evenly-sized groups
Notations:
Let name your text document="word1 word2 .... wordp"
n= number of line required
LineWidth=len(document)/n
Cost function:
First you need to define a cost function of having word[i] to word[j] in the same line , you can take the same as the one as the one on wikipedia, with p=2 for example:
It represent the distance between the objective length of a line and the actual lenght.
The total cost function for the optimal solution can be defined with the following recursiion relation:
Solving the problem:
You can solve this problem using dynamic programming.
I took the code from the link you gave, and changed it a so you see what the program is using.
At stage k you add words to line k.
Then you look at the optimal cost of
having word i to j at line k.
Once you've gone from line 1 to n,
you tacke the smallest cost in the
last step and you have your optimal
result:
Here is the result from the code:
D=minragged('Just testing to see how this works.')
number of words: 7
------------------------------------
stage : 0
------------------------------------
word i to j in line 0 TotalCost (f(j))
------------------------------------
i= 0 j= 0 121.0
i= 0 j= 1 49.0
i= 0 j= 2 1.0
i= 0 j= 3 16.0
i= 0 j= 4 64.0
i= 0 j= 5 144.0
i= 0 j= 6 289.0
i= 0 j= 7 576.0
------------------------------------
stage : 1
------------------------------------
word i to j in line 1 TotalCost (f(j))
------------------------------------
i= 0 j= 0 242.0
i= 0 j= 1 170.0
i= 0 j= 2 122.0
i= 0 j= 3 137.0
i= 0 j= 4 185.0
i= 0 j= 5 265.0
i= 0 j= 6 410.0
i= 0 j= 7 697.0
i= 1 j= 2 65.0
i= 1 j= 3 50.0
i= 1 j= 4 58.0
i= 1 j= 5 98.0
i= 1 j= 6 193.0
i= 1 j= 7 410.0
i= 2 j= 4 26.0
i= 2 j= 5 2.0
i= 2 j= 6 17.0
i= 2 j= 7 122.0
i= 3 j= 7 80.0
------------------------------------
stage : 2
------------------------------------
word i to j in line 2 TotalCost (f(j))
------------------------------------
i= 0 j= 7 818.0
i= 1 j= 7 531.0
i= 2 j= 7 186.0
i= 3 j= 7 114.0
i= 4 j= 7 42.0
i= 5 j= 7 2.0
reversing list
------------------------------------
Just testing 12
to see how 10
this works. 11
*There fore the best choice is to have words 5 to 7 in last line.(cf
stage2)
then words 2 to 5 in second line (cf
stage1)
then words 0 to 2 in first line (cf
stage 0).*
Reverse this and you get:
Just testing 12
to see how 10
this works. 11
Here is the code to print the reasonning,(in python sorry I don't use C#...but I someone actually translated the code in C#) :
def minragged(text, n=3):
P=2
words = text.split()
cumwordwidth = [0]
# cumwordwidth[-1] is the last element
for word in words:
cumwordwidth.append(cumwordwidth[-1] + len(word))
totalwidth = cumwordwidth[-1] + len(words) - 1 # len(words) - 1 spaces
linewidth = float(totalwidth - (n - 1)) / float(n) # n - 1 line breaks
print "number of words:", len(words)
def cost(i, j):
"""
cost of a line words[i], ..., words[j - 1] (words[i:j])
"""
actuallinewidth = max(j - i - 1, 0) + (cumwordwidth[j] - cumwordwidth[i])
return (linewidth - float(actuallinewidth)) ** P
"""
printing the reasoning and reversing the return list
"""
F={} # Total cost function
for stage in range(n):
print "------------------------------------"
print "stage :",stage
print "------------------------------------"
print "word i to j in line",stage,"\t\tTotalCost (f(j))"
print "------------------------------------"
if stage==0:
F[stage]=[]
i=0
for j in range(i,len(words)+1):
print "i=",i,"j=",j,"\t\t\t",cost(i,j)
F[stage].append([cost(i,j),0])
elif stage==(n-1):
F[stage]=[[float('inf'),0] for i in range(len(words)+1)]
for i in range(len(words)+1):
j=len(words)
if F[stage-1][i][0]+cost(i,j)<F[stage][j][0]: #calculating min cost (cf f formula)
F[stage][j][0]=F[stage-1][i][0]+cost(i,j)
F[stage][j][1]=i
print "i=",i,"j=",j,"\t\t\t",F[stage][j][0]
else:
F[stage]=[[float('inf'),0] for i in range(len(words)+1)]
for i in range(len(words)+1):
for j in range(i,len(words)+1):
if F[stage-1][i][0]+cost(i,j)<F[stage][j][0]:
F[stage][j][0]=F[stage-1][i][0]+cost(i,j)
F[stage][j][1]=i
print "i=",i,"j=",j,"\t\t\t",F[stage][j][0]
print 'reversing list'
print "------------------------------------"
listWords=[]
a=len(words)
for k in xrange(n-1,0,-1):#reverse loop from n-1 to 1
listWords.append(' '.join(words[F[k][a][1]:a]))
a=F[k][a][1]
listWords.append(' '.join(words[0:a]))
listWords.reverse()
for line in listWords:
print line, '\t\t',len(line)
return listWords
Here is the accepted solution from Algorithm to divide text into 3 evenly-sized groups converted to C#:
static List<string> Minragged(string text, int n = 3)
{
var words = text.Split();
var cumwordwidth = new List<int>();
cumwordwidth.Add(0);
foreach (var word in words)
cumwordwidth.Add(cumwordwidth[cumwordwidth.Count - 1] + word.Length);
var totalwidth = cumwordwidth[cumwordwidth.Count - 1] + words.Length - 1;
var linewidth = (double)(totalwidth - (n - 1)) / n;
var cost = new Func<int, int, double>((i, j) =>
{
var actuallinewidth = Math.Max(j - i - 1, 0) + (cumwordwidth[j] - cumwordwidth[i]);
return (linewidth - actuallinewidth) * (linewidth - actuallinewidth);
});
var best = new List<List<Tuple<double, int>>>();
var tmp = new List<Tuple<double, int>>();
best.Add(tmp);
tmp.Add(new Tuple<double, int>(0.0f, -1));
foreach (var word in words)
tmp.Add(new Tuple<double, int>(double.MaxValue, -1));
for (int l = 1; l < n + 1; ++l)
{
tmp = new List<Tuple<double, int>>();
best.Add(tmp);
for (int j = 0; j < words.Length + 1; ++j)
{
var min = new Tuple<double, int>(best[l - 1][0].Item1 + cost(0, j), 0);
for (int k = 0; k < j + 1; ++k)
{
var loc = best[l - 1][k].Item1 + cost(k, j);
if (loc < min.Item1 || (loc == min.Item1 && k < min.Item2))
min = new Tuple<double, int>(loc, k);
}
tmp.Add(min);
}
}
var lines = new List<string>();
var b = words.Length;
for (int l = n; l > 0; --l)
{
var a = best[l][b].Item2;
lines.Add(string.Join(" ", words, a, b - a));
b = a;
}
lines.Reverse();
return lines;
}
There was a discussion about this exact problem (though it was phrased in a different way) at http://www.perlmonks.org/?node_id=180276.
In the end the best solution was to do a binary search through all possible widths to find the smallest width that wound up with no more than the desired number of columns. If there are n items and the average width is m, then you'll need O(log(n) + log(m)) passes to find the right width, each of which takes O(n) time, for O(n * (log(n) + log(m))). This is probably fast enough with no more need to be clever.
If you wish to be clever, you can create an array of word counts, and cumulative lengths of the words. Then use binary searches on this data structure to figure out where the line breaks are. Creating this data structure is O(n), and it makes all of the passes to figure out the right width be O(log(n) * (log(n) + log(m))) which for reasonable lengths of words is dominated by your first O(n) pass.
If the widths of words can be floating point, you'll need to do something more clever with the binary searches, but you are unlikely to need that particular optimization.
btilly has the right answer here, but just for fun I decided to code up a solution in python:
def wrap_min_width(words, n):
r, l = [], ""
for w in words:
if len(w) + len(l) > n:
r, l = r + [l], ""
l += (" " if len(l) > 0 else "") + w
return r + [l]
def min_lines(phrase, lines):
words = phrase.split(" ")
hi, lo = sum([ len(w) for w in words ]), min([len(w) for w in words])
while lo < hi:
mid = lo + (hi-lo)/2
v = wrap_min_width(words, mid)
if len(v) > lines:
lo = mid + 1
elif len(v) <= lines:
hi = mid
return lo, "\n".join(wrap_min_width(words, lo))
Now this still may not be exactly what you want, since if it is possible to wrap the words in fewer than n lines using the same line width, it instead returns the smallest number of lines encoding. (Of course you can always add extra empty lines, but it is a bit silly.) If I run it on your test case, here is what I get:
Case: "I would like to be wrapped into three lines", 3 lines
Result: 14 chars/line
I would like to
be wrapped into
three lines
I just thought of an approach:
You can write a function accepting two parameters 1. String 2. Number of lines
Get the length of the string (String.length if using C#).
Divide the length by number of lines (lets say the result is n)
Now start a loop and access each character of the string (using string[i])
Insert a '\n\r' after every nth occurrence in the array of characters.
In the loop maintain a temp string array which would be null if there is a blank character(maintaining each word).
If there is a nth occurrence and temp string is not null then insert '\n\r' after that temp string.
I'll assume you're trying to minimize the maximum width of a string with n breaks. This can be done in O(words(str)*n) time and space using dynamic programming or recursion with memoziation.
The recurrence would look like this where the word has been split in to words
def wordwrap(remaining_words, n):
if n > 0 and len(remaining_words)==0:
return INFINITY #we havent chopped enough lines
if n == 0:
return len(remaining_words.join(' ')) # rest of the string
best = INFINITY
for i in range remaining_words:
# split here
best = min( max(wordwrap( remaining_words[i+1:], n-1),remaining_words[:i].join(' ')), best )
return best
I converted the C# accepted answer to JavaScript for something I was working on. Posting it here might save someone a few minutes of doing it themselves.
function WrapTextWithLimit(text, n) {
var words = text.toString().split(' ');
var cumwordwidth = [0];
words.forEach(function(word) {
cumwordwidth.push(cumwordwidth[cumwordwidth.length - 1] + word.length);
});
var totalwidth = cumwordwidth[cumwordwidth.length - 1] + words.length - 1;
var linewidth = (totalwidth - (n - 1.0)) / n;
var cost = function(i, j) {
var actuallinewidth = Math.max(j - i - 1, 0) + (cumwordwidth[j] - cumwordwidth[i]);
return (linewidth - actuallinewidth) * (linewidth - actuallinewidth);
};
var best = [];
var tmp = [];
best.push(tmp);
tmp.push([0.0, -1]);
words.forEach(function(word) {
tmp.push([Number.MAX_VALUE, -1]);
});
for (var l = 1; l < n + 1; ++l)
{
tmp = [];
best.push(tmp);
for (var j = 0; j < words.length + 1; ++j)
{
var min = [best[l - 1][0][0] + cost(0, j), 0];
for (var k = 0; k < j + 1; ++k)
{
var loc = best[l - 1][k][0] + cost(k, j);
if (loc < min[0] || (loc === min[0] && k < min[1])) {
min = [loc, k];
}
}
tmp.push(min);
}
}
var lines = [];
var b = words.length;
for (var p = n; p > 0; --p) {
var a = best[p][b][1];
lines.push(words.slice(a, b).join(' '));
b = a;
}
lines.reverse();
return lines;
}
This solution improves on Mikola's.
It's better because
It doesn't use strings. You don't need to use strings and concatenate them. You just need an array of their lengths. So, because of this it's faster, also you can use this method with any kind of "element" - you just need the widths.
There was some unnecessary processing in the wrap_min_width function. It just kept going even when it went beyond the point of failure. Also, it just builds the string unnecessarily.
Added the "separator width" as an adjustable parameter.
It calculates the min width - which is really what you want.
Fixed some bugs.
This is written in Javascript:
// For testing calcMinWidth
var formatString = function (str, nLines) {
var words = str.split(" ");
var elWidths = words.map(function (s, i) {
return s.length;
});
var width = calcMinWidth(elWidths, 1, nLines, 0.1);
var format = function (width)
{
var lines = [];
var curLine = null;
var curLineLength = 0;
for (var i = 0; i < words.length; ++i) {
var word = words[i];
var elWidth = elWidths[i];
if (curLineLength + elWidth > width)
{
lines.push(curLine.join(" "));
curLine = [word];
curLineLength = elWidth;
continue;
}
if (i === 0)
curLine = [word];
else
{
curLineLength += 1;
curLine.push(word);
}
curLineLength += elWidth;
}
if (curLine !== null)
lines.push(curLine.join(" "));
return lines.join("\n");
};
return format(width);
};
var calcMinWidth = function (elWidths, separatorWidth, lines, tolerance)
{
var testFit = function (width)
{
var nCurLine = 1;
var curLineLength = 0;
for (var i = 0; i < elWidths.length; ++i) {
var elWidth = elWidths[i];
if (curLineLength + elWidth > width)
{
if (elWidth > width)
return false;
if (++nCurLine > lines)
return false;
curLineLength = elWidth;
continue;
}
if (i > 0)
curLineLength += separatorWidth;
curLineLength += elWidth;
}
return true;
};
var hi = 0;
var lo = null;
for (var i = 0; i < elWidths.length; ++i) {
var elWidth = elWidths[i];
if (i > 0)
hi += separatorWidth;
hi += elWidth;
if (lo === null || elWidth > lo)
lo = elWidth;
}
if (lo === null)
lo = 0;
while (hi - lo > tolerance)
{
var guess = (hi + lo) / 2;
if (testFit(guess))
hi = guess;
else
lo = guess;
}
return hi;
};

Resources