Algorithm 将文本分成3个大小相等的组的算法
我想创建一个算法,将文本分成3个大小相等的组(基于文本长度)。由于这将用于换行符,因此需要保持文本的顺序 例如,此字符串:Algorithm 将文本分成3个大小相等的组的算法,algorithm,sorting,Algorithm,Sorting,我想创建一个算法,将文本分成3个大小相等的组(基于文本长度)。由于这将用于换行符,因此需要保持文本的顺序 例如,此字符串: Just testing to see how this works. 将排序为: Just testing // 12 characters to see how // 10 characters this works. // 11 characters 有什么想法吗?来自: 许多现代文字处理器都使用这种方法,如OpenOffice.org Wri
Just testing to see how this works.
将排序为:
Just testing // 12 characters
to see how // 10 characters
this works. // 11 characters
有什么想法吗?来自:
许多现代文字处理器都使用这种方法,如OpenOffice.org Writer和Microsoft word。这种算法是最优的,因为它总是将文本放在最少的行数上
对于初学者,您可以尝试下一个简单的启发式方法:将迭代器放置在n/3和2n/3中,并搜索每个迭代器附近的最近空间。同样来自Wikipedia关于word wrap的文章的“最小粗糙度”动态程序可以根据您的需要进行调整。设置
LineWidth=len(text)/n-1
,忽略关于超出线宽的无限惩罚的注释;使用c(i,j)
的定义,就像P=2
一样
“某人”的回答很好。但是,我在将其转换为SWIFT代码时遇到了问题。这是我给所有感兴趣的人的翻译
import Foundation
class SplitText{
typealias MinRag = (Float, Int) // meaning (cost for line (so far), word index)
// from http://stackoverflow.com/questions/6426017/word-wrap-to-x-lines-instead-of-maximum-width-least-raggedness?lq=1
class func splitText(text:String, numberOfLines:Int)-> [String]{
//preparations
var words = split(text, maxSplit:100, allowEmptySlices: false, isSeparator:{(s:Character)-> Bool in return s == " " || s == "\n"})
var cumwordwidth = [Int](); //cummulative word widths
cumwordwidth.append(0);
for word in words{
cumwordwidth.append(cumwordwidth[cumwordwidth.count - 1] + count(word));
}
var totalwidth = cumwordwidth[cumwordwidth.count - 1] + count(words) - 1;
var linewidth:Float = Float(totalwidth - (numberOfLines - 1)) / Float(numberOfLines)
// cost function for one line for words i .. j
var cost = { (i:Int,j:Int)-> Float in
var actuallinewidth = max(j - i - 1, 0) + (cumwordwidth[j] - cumwordwidth[i]);
var remainingWidth: Float = linewidth - Float(actuallinewidth)
return remainingWidth * remainingWidth
}
var best = [[MinRag]]()
var tmp = [MinRag]();
//ensure that data structure is initialised in a way that we start with adding the first word
tmp.append((0, -1));
for word in words {
tmp.append((Float.infinity , -1));
}
best.append(tmp);
//now we can start. We simply calculate the cost for all possible lines
for l in 1...numberOfLines {
tmp = [MinRag]()
for j in 0...words.count {
var min:MinRag = (best[l - 1][0].0 + cost(0, j), 0);
var k: Int
for k = 0; k < j + 1 ; ++k {
var loc:Float = best[l - 1][k].0 + cost(k, j);
if (loc < min.0 || (loc == min.0 && k < min.1)) {
min=(loc, k);
}
println("l=\(l), j=\(j), k=\(k), min=\(min)")
}
tmp.append(min);
}
best.append(tmp);
}
//now build the answer based on above calculations
var lines = [String]();
var b = words.count;
var o:Int
for o = numberOfLines; o > 0 ; --o {
var a = best[o][b].1;
lines.append(" ".join(words[a...b-1]));
b = a;
}
return reverse(lines);
}
}
<代码>导入基础
类拆分文本{
typealias MinRag=(Float,Int)//意思(行的成本(到目前为止),单词索引)
//从http://stackoverflow.com/questions/6426017/word-wrap-to-x-lines-instead-of-maximum-width-least-raggedness?lq=1
类func splitText(文本:String,numberOfLines:Int)->[String]{
//准备工作
var words=split(text,maxslit:100,allowEmptySlices:false,isSeparator:{(s:Character)->Bool返回s==“”| | s==“\n”})
var cumwordwidth=[Int]();//累积字宽
cumwordwidth.append(0);
一字不差{
append(cumwordwidth[cumwordwidth.count-1]+count(word));
}
var totalwidth=cumwordwidth[cumwordwidth.count-1]+count(words)-1;
变量linewidth:Float=Float(总宽度-(numberOfLines-1))/Float(numberOfLines)
//单词i..j的一行成本函数
var成本={(i:Int,j:Int)->浮动
var actuallinewidth=max(j-i-1,0)+(cumwordwidth[j]-cumwordwidth[i]);
var remainingWidth:Float=linewidth-Float(实际线宽)
返回剩余宽度*剩余宽度
}
var best=[[MinRag]]()
var tmp=[MinRag]();
//确保以我们从添加第一个单词开始的方式初始化数据结构
tmp.append((0,-1));
一字不差{
追加((Float.infinity,-1));
}
最佳附加(tmp);
//现在我们可以开始了。我们只需计算所有可能线路的成本
对于1…numberOfLines中的l{
tmp=[MinRag]()
对于0…单词中的j.count{
VarMin:MinRag=(最佳[l-1][0].0+成本(0,j),0);
变量k:Int
对于k=0;k如果您可以为n组而不是仅为3组获得奖励积分,则可获得奖励积分!)那么,您需要对文本进行排序还是拆分?有点不同,应该是n组大小相对相似的?请解释是什么决定了组的大小。忘记n组。只有3组尽可能接近大小。我认为这个问题不同于通常的单词包装。通常,您提前知道线宽,并且算法确定行数。在这里,你预先知道行数,算法决定了行宽。把字符串的长度除以你想要的行数怎么样?它至少会给出一个近似值。你能为此创建一些代码吗?我不明白你的意思(我读过关于最小粗糙度的书,它似乎正是我所需要的。但是我不知道如何将这个等式转换成可用的代码。有什么想法吗?呃……我正在尝试将它转换成Objective-C和Actionscript……但我在这两个方面都失败了。这是python脚本吗?我不喜欢如此相互依赖,但我只是可以不要解析它…即使有代码提示。好吧,这绝对是我要找的!非常感谢。我要看看是否能找到一个懂Python的朋友。这段代码是用Objective-C编写的,放在这里:我采用了Swift的代码,放在这里:
Code. I took the liberty of modifying the DP always to return exactly n lines, at the cost of increasing the running time from O(#words ** 2) to O(#words ** 2 * n).
def minragged(text, n=3):
"""
>>> minragged('Just testing to see how this works.')
['Just testing', 'to see how', 'this works.']
>>> minragged('Just testing to see how this works.', 10)
['', '', 'Just', 'testing', 'to', 'see', 'how', 'this', 'works.', '']
"""
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
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)) ** 2
# best[l][k][0] is the min total cost for words 0, ..., k - 1 on l lines
# best[l][k][1] is a minimizing index for the start of the last line
best = [[(0.0, None)] + [(float('inf'), None)] * len(words)]
# xrange(upper) is the interval 0, 1, ..., upper - 1
for l in xrange(1, n + 1):
best.append([])
for j in xrange(len(words) + 1):
best[l].append(min((best[l - 1][k][0] + cost(k, j), k) for k in xrange(j + 1)))
lines = []
b = len(words)
# xrange(upper, 0, -1) is the interval upper, upper - 1, ..., 1
for l in xrange(n, 0, -1):
a = best[l][b][1]
lines.append(' '.join(words[a:b]))
b = a
lines.reverse()
return lines
if __name__ == '__main__':
import doctest
doctest.testmod()
import Foundation
class SplitText{
typealias MinRag = (Float, Int) // meaning (cost for line (so far), word index)
// from http://stackoverflow.com/questions/6426017/word-wrap-to-x-lines-instead-of-maximum-width-least-raggedness?lq=1
class func splitText(text:String, numberOfLines:Int)-> [String]{
//preparations
var words = split(text, maxSplit:100, allowEmptySlices: false, isSeparator:{(s:Character)-> Bool in return s == " " || s == "\n"})
var cumwordwidth = [Int](); //cummulative word widths
cumwordwidth.append(0);
for word in words{
cumwordwidth.append(cumwordwidth[cumwordwidth.count - 1] + count(word));
}
var totalwidth = cumwordwidth[cumwordwidth.count - 1] + count(words) - 1;
var linewidth:Float = Float(totalwidth - (numberOfLines - 1)) / Float(numberOfLines)
// cost function for one line for words i .. j
var cost = { (i:Int,j:Int)-> Float in
var actuallinewidth = max(j - i - 1, 0) + (cumwordwidth[j] - cumwordwidth[i]);
var remainingWidth: Float = linewidth - Float(actuallinewidth)
return remainingWidth * remainingWidth
}
var best = [[MinRag]]()
var tmp = [MinRag]();
//ensure that data structure is initialised in a way that we start with adding the first word
tmp.append((0, -1));
for word in words {
tmp.append((Float.infinity , -1));
}
best.append(tmp);
//now we can start. We simply calculate the cost for all possible lines
for l in 1...numberOfLines {
tmp = [MinRag]()
for j in 0...words.count {
var min:MinRag = (best[l - 1][0].0 + cost(0, j), 0);
var k: Int
for k = 0; k < j + 1 ; ++k {
var loc:Float = best[l - 1][k].0 + cost(k, j);
if (loc < min.0 || (loc == min.0 && k < min.1)) {
min=(loc, k);
}
println("l=\(l), j=\(j), k=\(k), min=\(min)")
}
tmp.append(min);
}
best.append(tmp);
}
//now build the answer based on above calculations
var lines = [String]();
var b = words.count;
var o:Int
for o = numberOfLines; o > 0 ; --o {
var a = best[o][b].1;
lines.append(" ".join(words[a...b-1]));
b = a;
}
return reverse(lines);
}
}