challenge 与えられた文字列でピラミッド

ピラミッドを作る」の続編です。 与えられた文字列を使って下の例のようなピラミッドを書いてください。 頂点は与えられた文字列の最後の一文字、 底辺は与えられた文字列の各文字の間に空白が入ったものになります。
>>> pyramid("hoge")
   e   
  g e  
 o g e 
h o g e
>>> pyramid("abracadabra")
          a          
         r a         
        b r a        
       a b r a       
      d a b r a      
     a d a b r a     
    c a d a b r a    
   a c a d a b r a   
  r a c a d a b r a  
 b r a c a d a b r a 
a b r a c a d a b r a

Posted feedbacks - Flatten

Nested Hidden
末尾の空白の数がサンプル出力と違いますが、題意になかったのでスルーしました。

chainは引数のイテレータを順番に実行するイテレータを返す関数です。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
pyramid: fun(str) {
    space: [" "].cycle;
    arr: str.split("").to_a;
    n: arr.length;
    n.times.map(|i| i + 1){
        chain(space.take(n - it ),
              arr.slice(n - it, n).zip(space).map(|a,b| a~b)).join("").p;
    }
}

pyramid("hoge");
pyramid("abracadabra");

文字を1文字づつ配列にするメソッドがあるのかどうかわからないので作りました。
Sequence split は 引数をあたえないと空白でわけるようです。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Sequence splitEvery := method(
    l := list()
    self foreach(v, 
        l append(v asCharacter)
    )   
    return l
)
pyramid := method(str,
    t := str size * 2 - 1 
    for(i, 1, str size,
        str slice(str size - i, str size) splitEvery join(" ") alignCenter(t, " ") println 
    )   
)


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
String.prototype.repeat = function(n) {
    for(var i=0, str=""; i < n; i++) {
        str += this;
    }
    return str;
}

String.prototype.alignCenter = function(n, str) {
    var r = (n - this.length) / 2;
    return str.repeat(r) + this + str.repeat(r);
}

var pyramid = function(str) {
    var t = str.length * 2 - 1
    var res = ""
    for(var i=1, len=str.length; i<=len; i++) {
        res += str.slice(str.length - i, str.length).split("").join(" ").alignCenter(t, " ") + "\n"
    }
    return res;
}

String.alignCenter を修正
1
2
3
4
String.prototype.alignCenter = function(n, str) {
    var r = (n - this.length) / 2
    return str.repeat(Math.floor(r)) + this + str.repeat(Math.ceil(r));
}

瞬殺
1
str="abracadabra"; (str.length-1).downto(0) {|i| print(" "*i, str[i..-1].split(//).join(" "),"\n") }

キモいコードでごめんなさい。
1
2
3
4
5
6
7
sub pyramid {
    my $i = my @py = split //, $_[0];
    print ' ' x $i . "@py[$i..$#py]\n" while $i--;
}

pyramid('hoge');
pyramid('abracadabra');


	
1
2
3
4
5
6
7
8
9
function pyramid(str)
  len = string.len(str)
  for i=len, 1, -1 do
    io.stdout:write(string.rep(" ",i-1))
    for j=i, len, 1 do io.stdout:write(string.sub(str,j,j), " ") end
    io.stdout:write("\n")
  end
end
pyramid("abracadabra")

Scheme用SLIMEがあればいいのに…
1
2
3
4
5
6
7
8
(use srfi-1)
(define (pyramid str)
  (map
   (lambda (i)
     (format #t "~a~a~%" (make-string i)
             (string-join (map string (string->list str i (string-length str))) " ")))
   (iota (- (string-length str) 0) (- (string-length str) 1) -1)))
(pyramid "abracadabra")

loop以外で部分文字列の取り方がわからんorz
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
(defun pyramid (str)
  (loop for i from (1- (length str)) downto 0 do
       (format t "~a~a~%"
               (make-string i :initial-element #\Space)
               (apply #'concatenate 'string
                      (loop for c across str
                         for j from 0
                         when (<= i j)
                         collect (format nil "~c~a" c " "))))))
(pyramid "abracadabra")


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include <stdio.h>

void pyramid(char *str) {
    int i,j,len;
    len = strlen(str);
    for (i=len-1; i>=0; i--) {
        for(j=0; j<i; j++) printf(" ");
        for(j=i; j<len; j++) printf("%c%c", str[j], ' ');
        printf("\n");
    }
}

int main() {
    pyramid("abracadabra");
    return 0;
}

C書いた直後にDを書くと、文字列の扱いを混同してしまった
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
private import std.stdio;

void pyramid(char[] str) {
    int i,j;
    for (i=str.length-1; i>=0; i--) {
        for(j=0; j<i; j++) writef(" ");
        for(j=i; j<str.length; j++) writef("%s%s", str[j], " ");
        writef("\n");
    }
}

int main() {
    pyramid("abracadabra");
    return 0;
}


	
1
2
3
4
5
6
7
8
(require 'cl)
(defun pyramid (str)
  (interactive "sPyramid string: ")
  (with-output-to-temp-buffer "*Pyramid*"
    (loop for i from (1- (length str)) downto 0 do
          (princ (make-string i ? ))
          (princ (mapconcat 'identity (split-string (substring str i) "") " "))
          (terpri))))

Cと変わらねえww
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function pyramid () {
    str=$1
    len=`expr length $str`
    for ((i=$len; i>=1; i--)); do
        for ((j=0; j<$i; j++)); do echo -n ' '; done
        for ((j=$i; j<=$len; j++)); do
            echo -n `expr substr $str $j 1`' '
        done
        echo
    done
}
pyramid "abracadabra"

文字列のインデックスアクセスも算術演算も明示的ループも無しで。
1
2
3
4
5
6
(use util.list)
(define (pyramid s)
  (let r ((s (string->list s)) (p '()))
    (unless (null? s)
      (r (cdr s) (cons #\ p))
      (apply print (append p (intersperse #\  s))))))

明示的算術演算なし版。自分では再帰も書かない版です。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import Data.List

binapp o f g x = f x `o` g x
pyramid = binapp (zipWith (++)) (map (map (const ' ')) . tail . tails)
                                (map (intersperse ' ') . tail . inits)
printPyramid = putStr . unlines . pyramid

{-
*Main> printPyramid "abracadabra"
          a
         a b
        a b r
       a b r a
      a b r a c
     a b r a c a
    a b r a c a d
   a b r a c a d a
  a b r a c a d a b
 a b r a c a d a b r
a b r a c a d a b r a
-}

% awk -f pyramid.awk hogehogehoge
           e 
          g e 
         o g e 
        h o g e 
       e h o g e 
      g e h o g e 
     o g e h o g e 
    h o g e h o g e 
   e h o g e h o g e 
  g e h o g e h o g e 
 o g e h o g e h o g e 
h o g e h o g e h o g e 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
BEGIN {
	if (length(ARGV[1]) > 0) printf pyramid(ARGV[1])
}

function pyramid(str,  N,moji,i,j)
{
	N = split(str,moji,"")

	s = ""
	a = moji[1]; for (i=2; i<=N; i++) a = a " " moji[i]  ## a = moji.join(' ')
	for (i=N; i>=1; i--) {
		s = a "\n" s
		sub(/[a-z]/,"",a)  ## 先頭から1文字ずつ消していく
	}
	return s
}


	
1
2
3
4
5
6
def pyramid(s):
	for i in range(len(s)):
		print ' '.join(s[~i:]).center(len(s)*2-1)

pyramid('hoge')
pyramid('abracadabra')

名前付きletは明示的loopじゃないと?:)

だめじゃんこれ、題意を読み違えてる。

題意を読み違えてたので再投稿
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Data.List

binapp o f g x = f x `o` g x
pyramid = binapp (zipWith (++)) (map (map (const ' ')) . tail)
                                (map (intersperse ' ') . tail . reverse)
        . tails
printPyramid = putStr . unlines . pyramid

{-
*Main> printPyramid "abracadabra"
          a
         r a
        b r a
       a b r a
      d a b r a
     a d a b r a
    c a d a b r a
   a c a d a b r a
  r a c a d a b r a
 b r a c a d a b r a
a b r a c a d a b r a
-}


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php
function pyramid($data) {
	$stclm = strlen($data);
	for ( $i = strlen($data) - 1; $i > -1; $i-- ) {
		$stclm--;
		echo str_pad("",$stclm," ",STR_PAD_LEFT);
		for ( $j = $i; $j < strlen($data); $j++ ) {
			echo substr($data,$j,1)." ";
		}
		echo "\n";
	}
}

pyramid("hoge");
pyramid("abracadabra");
?>


	
1
2
3
4
5
6
def pyramid(s:String) = {
  val (len, cs) = (s.size-1, s.toList)
  len.until(-1,-1).map(cs.splitAt).foreach{p =>
    println((p._1.map(x=>""):::p._2).mkString(" "))
  }
}

>部分文字列の取り方
subseq です?


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>

void pyramid(const std::string& s)
{
    for (std::string::const_iterator it = s.end(); it != s.begin(); --it)
    {
        const size_t n = std::distance(s.begin(), it - 1);

        std::fill_n(std::ostream_iterator<char>(std::cout), n, ' ');

        std::copy(it - 1, s.end() - 1, std::ostream_iterator<char>(std::cout, " "));

        std::cout << *(s.end() - 1);

        std::fill_n(std::ostream_iterator<char>(std::cout), n, ' ');

        std::cout << std::endl;
    }
}

int main()
{
    pyramid("hoge");
    pyramid("abracadabra");
}

まとめてprint
1
2
3
4
5
def pyramid(s):
  print '\n'.join([' '*i + ' '.join(s[i:]) for i in range(len(s)-1, -1, -1)]),

pyramid('hoge')
pyramid('abracadabra')

phpって変な関数いっぱいあるな。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function pyramid($str) {
    $splt;
    for ($i = 0; $i < strlen($str); $i++) {
        $s = str_split(substr($str,$i,strlen($str)));
        $splt[] = str_repeat(" ", $i) .join(" ",$s);
    }
    krsort($splt);
    return join("\n",$splt);
}
echo pyramid("abracadabra");

名前付けてるだけだも〜ん。 それにいわゆる「ループとしての使いかた」はしてないし。

上記は英語のみ。
日本語混ざると死にます。

Never mind ! :)

 シンプルに。

javascript:(function(p,r,m,d){for(p=p.split(''),r=[],m=p.length,d=0;m--;p[d++]='')r[m]=p.join(' ');return'<pre>'+r.join('\n')+'</pre>'})('abracadabra')
1
2
3
4
5
function pyramid(s){
  s = s.split('');
  for(var r = [], i = s.length, j = 0; i--; s[j++] = "") r[i] = s.join(' ');
  return r.join('\n');
}

Squeak Smalltalk で。
1
2
3
4
5
6
| input |
input := 'abracadabra'.
World findATranscript: nil.
1 to: input size do: [:len |
	Transcript cr; show: (String new: input size - len withAll: $ ).
	(input last: len) do: [:each | Transcript show: each] separatedBy: [Transcript space]]

Rubyに対する対抗意識w
1
s="abracadabra";n=len(s);print"\n".join(" ".join(s[~i:]).center(n*2-1)for i in range(n))


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class Pyramid {
	public static void main(String[] args) {
		String data = args.length > 0 ? args[0] : "abracatabra";
		char[] spaceChars = new char[data.length()-1];
		java.util.Arrays.fill(spaceChars, ' ');
		String space = new String(spaceChars);
		
		for(int i=0;i<data.length();i++) {
			System.out.println(space.substring(i)
					+ data.substring(data.length()-1-i).replaceAll("(.)(?=.)","$1 "));
		}
	}
}

お、phpの投稿が増えてる。
ということで私なりに…。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php
function pyramid($str)
{
    $len=strlen($str);
    $str=implode(" ",str_split($str));
    for($i=1;$i<=$len;++$i)
    	echo str_repeat(" ", $len-$i),substr($str,-($i*2-1)),"\n";
}
echo pyramid("abracadabra");
?>

ぐはっ。9行目のechoは余計…。コピーしたのもろバレ。
ということでついでに別解。
空の文字列の並んだ配列をスペース挟んで繋ぐと
勝手にセンタリングされるという…。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php
function pyramid($str)
{
	$i=strlen($str);
	$a=array_fill( 0, $i, "");
	while(--$i>=0)
	{	$a[$i]=$str[$i];
		echo implode(" ",$a),"\n";
	}
}

pyramid("abracadabra");
?>


	
1
2
3
4
5
6
7
8
9
Sub pyramid(ByVal block As String)
    For i As Integer = 0 To block.Length - 1
        Dim line As String = Space(block.Length - i - 1)
        For j As Integer = 0 To i
            line &= " " & block.Substring(block.Length - i - 1 + j, 1)
        Next
        Console.WriteLine(line.Substring(1))
    Next
End Sub


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <string.h>

void put_s(int n)
{
	int i;
	for (i = 0; i < n; i++) putchar(' ');
}

void put_c(const char *s)
{
	putchar(*s);
	
	while (*++s) {
		putchar(' ');
		putchar(*s);
	}
}
void pyramid(const char *s)
{
	int n;

	n = strlen(s);
	
	while (--n >= 0) {
		put_s(n);
		put_c(s + n);
		put_s(n);
		putchar('\n');
	}
}

int main()
{
	pyramid("hoge");
	pyramid("abracadabra");
	return 0;
}

REPLと二人三脚で作りました。
1
2
3
4
5
6
7
8
9
(defun pyramid (str)
  (let ((base (coerce (cdr (reduce (lambda (r x) `(,@r #\Space ,x))
				   (coerce str 'list)
				   :initial-value '())) 'string)))
    (do ((idx 2 (+ idx 2))
	 (len (length base))
	 (result base (concatenate 'string spacer (subseq base idx) "~%" result))
	 (spacer " " (concatenate 'string " " spacer)))
	((> idx len) (format t result)))))

ベタに書いてみました
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php

$p_mess="hoge";
echo "<textarea cols=100 rows=20>";
echo pyramid($p_mess);
echo "</textarea>";


$p_mess="abracadabra";
echo "<textarea cols=100 rows=20>";
echo pyramid($p_mess);
echo "</textarea>";

function pyramid($p_mess)
{
	$p_len=strlen($p_mess);
	for($i=1;$i<=$p_len;$i++)	//縦方向ループ
	{
		$w="";
		for($j=$p_len-$i;$j<=$p_len;$j++)	//横方向ループ、x行目=後ろからx文字分をループ
		{
			$w.=substr($p_mess,$j,1)." ";	//切り出し+空白文字をwに入れ込む
		}
		
		$w=str_pad($w,$p_len*2+1," ",STR_PAD_BOTH);	//左右に[ ]を埋める
		$ret.=rtrim($w)."\n";	//右側の空白ははずす
	}
	return $ret;
}

?>

あえてリストベースで format 頼りの処理.
コードの長さが気になるが恥さらしで.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
(defun pyramid (string)
  (let ((chars (coerce string 'list)) (floors nil))
	(labels
		((make-floors (list n-space)
		   (unless (null list)
			 (push (format nil "~{~A~}~{~A~^ ~}~%"
						   (make-list n-space :initial-element #\Space) list)
				   floors)
			 (make-floors (cdr list) (1+ n-space)))))
	  (make-floors chars 0))
	(mapcan #'(lambda (string)
				(format t "~A" string))
			floors)))


	
1
2
3
4
5
6
7
8
<?php
function pyramid($str){
	for($i=$j=$n=strlen($str); $i>0; $i--, $n=$j*2-$i)
		printf("% {$n}s\n", trim(join(" ", preg_split("//", substr($str, $i-1, $j)))));
}

pyramid("abracadabra");
?>

Control.Arrowを中途半端につかってみました。

*Main> pyramid "abracadabra"
          a
         r a
        b r a
       a b r a
      d a b r a
     a d a b r a
    c a d a b r a
   a c a d a b r a
  r a c a d a b r a
 b r a c a d a b r a
a b r a c a d a b r a
1
2
3
4
5
import Control.Arrow
import Data.List (tails,intersperse)

pyramid = id &&& length >>> first (tails >>> reverse >>> tail >>> map (id &&& length)) >>> uncurry f
    where f xs len = mapM_ (\(x,y) -> putStrLn $ (++) (replicate (len - y) ' ') $ intersperse ' ' x) xs

maplist できれいに書けそうに思ったのですがスペースの調整が美しくなく、
結局 loop のほうがすっきりした形になりました。
1
2
3
4
(defun pyramid (string)
  (loop for x on (coerce string 'list) for i from 0 with tmp
     collect (format nil "~VT,0~{~A~^ ~}" i x) into tmp
     finally (mapc #'write-line (nreverse tmp))))

ごめんなさい間違ったものを送信してしまいました。
こっちが正しいコードです。
1
2
3
4
(defun pyramid (string)
  (loop for x on (coerce string 'list) for i from 0
    collect (format nil "~V,0T~{~A~^ ~}" i x) into tmp
    finally (mapc #'write-line (nreverse tmp))))

素直にループで。 今見ると#689の冗長さが何とも・・・。

1
2
3
pyramid <- function(s, n=nchar(s), s2=unlist(strsplit(s, ''))){
   for(i in n:1) cat(c(character(i-1), s2[i:n]), fill=TRUE)
}

PHP、ありそうでなかった再帰版。
超シンプル!
1
2
3
4
5
function pyramid( $str, $_=''){
   echo strlen($str)? pyramid( substr($str,1), "$_ ")."\n$_"
      : null, join( ' ', preg_split('//',$str));
}
pyramid('abracadabra');

初めて投稿します。
Traversableを使って手続き型言語っぽく書いてみました。

*Main> pyramid "abracadabra"
          a
         r a
        b r a
       a b r a
      d a b r a
     a d a b r a
    c a d a b r a
   a c a d a b r a
  r a c a d a b r a
 b r a c a d a b r a
a b r a c a d a b r a
1
2
3
4
5
6
7
8
9
import Data.List
import Data.Traversable

pyramid str = do 
    for (reverse $ p str) putStrLn 
    return ()
  where
    p (x:xs) = (intersperse ' ' (x:xs)) : map (' ':) (p xs)
    p [] = []

ちょっと修正。
trim取ったり、substrの引数取ったり。
1
2
3
4
5
6
7
8
<?php
function pyramid($str){
	for($i=$n=strlen($str); $i>=0; $i--, $n=strlen($str)*2-$i+1)
		printf("% {$n}s\n", join(" ", preg_split("//", substr($str, $i))));
}

pyramid("abracadabra");
?>

なるほど。似たアルゴリズムでControl.Applicableを使わないで書いてみた。

zipWith (flip const) xs ≡ take (length xs)
です。(個人的ポリシーによりlengthはなるだけ使わない)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import Data.List

pyramid :: String -> [String]
pyramid xs
 = map bar                     -- 片リストから行リストへ
 $ reverse                     -- リストを反転,上片から下片へ
 $ zipWith (flip const) xs     -- xs の長さ分切り取る
 $ iterate foo ("",xs)         -- 下片から上片へのリスト

foo :: (String, String) -> (String, String)
foo (indent,str) = (' ':indent, tail str)         -- 下片から1つ上片を求める
bar :: (String,String) -> String
bar (indent,str) = indent ++ intersperse ' ' str  -- 片から行へ変換

{-
*Main> putStr $ unlines $ pyramid "hoge"
   e
  g e
 o g e
h o g e
-}

さらに starling と binapp' を用いて
pyramid をポイントフリースタイルに書きなおしたもの
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import Data.List

starling f g x = f x (g x)
binapp' o f g x y = f x `o` g y

pyramid' = map (uncurry bar') . reverse . starling (zipWith (flip const)) (iterate (uncurry foo') . ((,) ""))

foo' = binapp' (,) (' ':) tail
bar' = binapp' (++) id (intersperse ' ')

{-
*Main> putStr $ unlines $ pyramid' "hage"
   e
  g e
 a g e
h a g e
-}

そうか、ということは unfoldr でも簡単に書けるんだ。
なるほど。。。勉強になるなぁ。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import Data.List

pyramid :: String -> [String]
pyramid = reverse . unfoldr phi . (,) ""
  where 
     phi (_ ,"")         = Nothing
     phi (xs,yys@(_:ys)) = Just (xs ++ intersperse ' ' yys,(' ':xs,ys))

{-
*Main> putStr $ unlines $ pyramid "hoge"
   e
  g e
 o g e
h o g e
-}

デフォルト引数を使って単独の関数で再帰実装。

最下段の取り扱いが納得いかない。
全部returnで書きたいのだが・・・。

長さ0文字の文字列には対応しておりません。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
"""
>>> pyramid("hoge")
   e
  g e
 o g e
h o g e

>>> pyramid("abracadabra")
          a
         r a
        b r a
       a b r a
      d a b r a
     a d a b r a
    c a d a b r a
   a c a d a b r a
  r a c a d a b r a
 b r a c a d a b r a
a b r a c a d a b r a
"""
def pyramid(s, padding=None):
  assert(len(s) > 0)
  if padding is None:
    padding = ' '
  if len(s) == 1:
    return s[0]
  else:
    p = pyramid(s[1:], padding + ' ')
    print padding + p
    if padding == ' ':
      print s[0] + ' ' + p
    else:
      return s[0] + ' ' + p

import doctest
doctest.testmod()

あまり長くない文字列なら再帰でも行けます。
(Emacsは再帰の深さが変数max-lisp-eval-depthで制限されるので事実上使えない)

(pyramid "abracadabra")
          a
         r a
        b r a
       a b r a
      d a b r a
     a d a b r a
    c a d a b r a
   a c a d a b r a
  r a c a d a b r a
 b r a c a d a b r a
a b r a c a d a b r a
1
2
3
4
(defun pyramid (s &optional p)
  (unless (string= s "")
    (pyramid (substring s 1) (cons ? p))
    (insert (concat p) (mapconcat #'string s " ") "\n")))


	
1
2
3
4
5
6
def strPyramid(s="abracadabra"):
    s      = " ".join(s)
    length = len(s)        
    
    for i in range(length)[::-2]:
        print s[i:].center(length,' ')

みなさんの投稿を参考にしつつ初投稿。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let pyramid str =
  let rec letters = function
    | "" -> []
    | s  -> (String.sub s 0 1) :: (letters (String.sub s 1 (String.length s - 1)))
  in
  fst (List.fold_right (fun s t -> let x = s ^ snd t in (x :: (fst t), " " ^ x))
                       (letters str) ([], ""))
  |> List.mapi (fun i s -> (String.make i ' ') ^ s) |> List.rev |> String.concat "\n";;

let _ = pyramid "abracadabra" |> printf "%s\n";;

\nをデリミタにしています。(\nh o g e)
1.1番目の項目を手前にコピー
2.ピラミッド一段上の形に合わせる
3.合わせたものが空白で埋まっていなければループ

最後に先頭の無駄な改行消してドン。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#!/bin/sed -f
s/ //g
s/./ &/g
s/^ /\n/

:loop
s/^\n[^\n]*/&&/
s/^\(\n *\)[^ ] /\1 /
s/\n/ \n/2
/^\n *\n/!b loop

s/^\n *\n//

PS C:\> pyramid
          a
         r a
        b r a
       a b r a
      d a b r a
     a d a b r a
    c a d a b r a
   a c a d a b r a
  r a c a d a b r a
 b r a c a d a b r a
a b r a c a d a b r a
PS C:\> pyramid("hoge")
   e
  g e
 o g e
h o g e
1
2
3
4
5
6
7
function pyramid($s = "abracadabra") {
     for ($i = 1; $i -le $s.length; $i++) {
          $p = $s[-$i..-1]
          $len = $s.length - $p.length
          " " * $len + $p
     }
}

#include <stdio.h>
#include <stdlib.h>

void pyramid(char* p)
{
    int i, j, n = strlen(p);
    char* buff = (char*)_alloca(n * n * 2);
    memset(buff, ' ', n * n * 2);
    for (i = 0; i < n; i++)
    {
        for (j = n * 2 * i + n - i - 1; j < n * n * 2; j += n * 2 + 1)
        {
            *(buff + j) = *(p + n - i - 1);
        }
        printf("%.*s\n", n * 2, buff + i * n * 2);
    }
}

int main(int argc, char* argv[])
{
    pyramid(argv[1]);
}

投稿し直し。2重ループ
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
 #include <stdio.h>
#include <stdlib.h>

void pyramid(char* p)
{
    int i, j, n = strlen(p);
    char* buff = (char*)_alloca(n * n * 2);
    memset(buff, ' ', n * n * 2);
    for (i = 0; i < n; i++)
    {
        for (j = n * 2 * i + n - i - 1; j < n * n * 2; j += n * 2 + 1)
        {
            *(buff + j) = *(p + n - i - 1);
        }
        printf("%.*s\n", n * 2, buff + i * n * 2);
    }
}

int main(int argc, char* argv[])
{
    pyramid(argv[1]);
}


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
using System;
using System.Text.RegularExpressions;

class Program {
    static void pyramid(string s) {
        int len = s.Length;
        s = Regex.Replace(s, "(.)(?=.)", @"$1 ");
        for (int n = len - 1; n >= 0; n--)
            Console.WriteLine(s.Substring(n * 2).PadLeft(len * 2 - n).PadRight(len * 2));
    }
    static void Main(string[] args) {
        pyramid("hoge");
        pyramid("abracadabra");
    }
}


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#include <iostream>
#include <string>

void pyramid(const std::string& src)
{
    const int   strLength = src.size();
    const int   lineLength = strLength * 2 - 1;
    std::string line(strLength, ' ');
    for(int i = strLength - 1; i >= 0; --i)
    {
        line[i] = src[i];
        std::cout << line.substr(0, lineLength) << std::endl;
        line = ' ' + line;
    }
}

最初に思いついたもの。酷い。
1
2
3
def pyramid str
str.chomp.reverse.gsub(/./){([" "*$'.size]*2)*(($`+$&).reverse.scan(/./)*" ")+$/}
end

ごり押し。
もっと分かり易くてうまいやり方があるはず。
1
2
3
4
5
6
7
8
9
def pyramid(str)
  n = str.length
  1.upto(n) do |i|
    result_str = str.split('').last(i).join
    spaces = " " * (n - i)
    puts result_str.split('').join(' ').insert(0, spaces)
  end
end
pyramid("piyohoge")

ごり押しに変わりは無い。
表示させる文字列をあらかじめ String#reverse
と String#split で反転・分解しておいた。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
def pyramid(str)
  n = str.length
  reversed_str_ary = str.reverse.split('')
  n.times do |i|
    result_str = reversed_str_ary[0..i].join
    spaces = " " * (n - i)
    puts result_str.split('').join(' ').insert(0, spaces)
  end
end
pyramid("piyohoge")

これじゃダメだった。 このままだと、文字列が反転したまま表示されてしまう。

pyramid
などの、引数の個数が0の場合を考えてなかったので、
pyramid(str = '')
として、デフォルトで空文字列を与えた。
1
2
3
4
5
6
7
8
def pyramid(str = '')
  n = str.length
  1.upto(n) do |i|
    result_str = str.split('').last(i).join
    spaces = " " * (n - i)
    puts result_str.split('').join(' ').insert(0, spaces)
  end
end

見た目がいかにも再帰っぽいと
再帰で書きたくなります。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
def pyramid(str, space = "")
  if str == ""
    ""
  else
    pyramid(str[1, str.size-1], space+" ") +
      space+str.split(//).join(" ")+"\n"
  end
end

print pyramid("hoge")
print pyramid("abracadabra")

formatでセンタリング, 32=スペースで
1
2
3
4
5
6
7
8
pyramid_sub([], _, []).
pyramid_sub([C|S], W, [32, C|S1]) :- pyramid_sub(S, W, S1),
	format('~t~s~t~*|~n', [[C|S1], W]).

pyramid(S) :- length(S, N), W is (N * 2) - 1, pyramid_sub(S, W, _).

:- pyramid("hoge").
:- pyramid("abracadabra").

なんとかできた感じ、作った後にスライス使えばよかったなぁと後悔。
1
2
3
4
5
6
7
8
9
def pyramid(s):
    row=s[-1]
    print ' '*(len(s)-1)+row
    for i in range(2,len(s)+1):
        row=s[-i]+' '+row
        print ' '*(len(s)-i)+row

if __name__=='__main__':
    pyramid('abracadabra')


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    call pyramid "hoge";
    call pyramid "abracadabra";
    endmacro;

pyramid:
    ##len = strlen( $$1 );
    ##i = ##len - 1;
    while( ##i >= 0 ) {
        ##j = ##i;
        while( ##j > 0 ) {
            insert " ";
            ##j = ##j - 1;
        }
        ##j = ##i;
        while( ##j < ##len ) {
            insert midstr( $$1, ##j, 1 );
            insert " ";
            ##j = ##j + 1;
        }
        insert "\n";
        ##i = ##i - 1;
    }
    return;


	
1
2
3
4
5
6
7
8
9
「abracadabra」のピラミッドを表示
●ピラミッド(sの)
    tとは配列
    ケタ数=(2*バイト数(s)-1)
    (バイト数(s))回
        tに(文字列センタリング(文字列注入(RIGHT(s,回数)," "),ケタ数))を配列追加
    tで戻る
●文字列注入(sにlを)
    sを文字列分解してlで配列結合で戻る


	
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <string.h>

void print_pyramid(const char* s)
{
  int i, j;
  int n = strlen(s);
  
  for (i=0; i<n; i++) {
    for (j=n-i-2; j>=0; j--) putchar(' ');
    for (j=n-i-1; j<n-1; j++) {
      putchar(s[j]);
      putchar(' ');
    }
    putchar(s[j]);
    puts("");
  }
}

int main(int argc, char** argv)
{
  print_pyramid("hoge");
  print_pyramid("abracadabra");
  return 0;
}

なるほど。~iか。みんなの読んでると勉強なります。

1
2
3
4
5
6
def pyramid(s):
  for i in range(len(s)-1, -1, -1):
    print " "*i + " ".join(s[i:])

pyramid("hoge")
pyramid("abracadabra")

   pyramid2 'abracadabra'
          a          
         r a         
        b r a        
       a b r a       
      d a b r a      
     a d a b r a     
    c a d a b r a    
   a c a d a b r a   
  r a c a d a b r a  
 b r a c a d a b r a 
a b r a c a d a b r a
1
pyramid2=.3 :'(,&a:<\.(<:#y)#'' ''),&;/"0([,'' '',])/&.>|.<\.y'

適当。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
fun pyramid s =
let
  fun loop s' NONE = []
    | loop s' (SOME c) =
    let
      val ns = subst (str c) "" s'
    in
      loop ns (CharVector.find Char.isGraph ns) @ [s']
    end

  val ss = (String.concatWith " " o global_slice ".") s
in
  (app println o loop ss o SOME o sub) (ss, 0)
end

val _ = pyramid "hoge"
val _ = pyramid "abracadabra"

段階的に目的の文字列へ近づけ、最後に出力します。

1> c(string_pyramid).
{ok,string_pyramid}
2> string_pyramid:string_pyramid("hoge").
   e
  g e
 o g e
h o g e
ok
3> string_pyramid:string_pyramid("abracadabra").
          a
         r a
        b r a
       a b r a
      d a b r a
     a d a b r a
    c a d a b r a
   a c a d a b r a
  r a c a d a b r a
 b r a c a d a b r a
a b r a c a d a b r a
ok
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
-module(string_pyramid).
-import(lists, [flatmap/2, foreach/2, nthtail/2, seq/2]).
-import(string, [centre/2, len/1, strip/3]).
-export([string_pyramid/1]).

string_pyramid(Str) ->
    L1 = [nthtail(len(Str) - X, Str) || X <- seq(1, len(Str))],
    L2 = [flatmap(fun(Y) -> [Y, " "] end, X) || X <- L1],
    L3 = [centre(strip(X, both, " "), len(Str) * 2 - 1) || X <- L2],
    foreach(fun(X) -> io:format("~s~n", [X]) end, L3).

再帰的に処理しつつpyramid関数の引数の数を変えないために, 新たにrecurs関数を定義しました.

1
2
3
4
5
6
7
8
def pyramid(str)
  def recurs(str, i, spc = ' ')
    puts "#{spc*i}#{str[i..-1].split('').join(spc)}"
    recurs(str, i-1) if i >= 1
  end
  recurs(str, str.size-1)
end
pyramid("abracadabra")

1
2
3
4
5
6
7
let pyramid s =
  let len = String.length s in
  for spc = (len-1) downto 0 do
    print_string (String.make spc ' ');
    String.iter (Printf.printf "%c ") (String.sub s (spc) (len-spc));
    print_newline ();
  done;;

遅レスですが#160を参考につくってみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
#include <string.h>

void pyramid(char* p) {

    int i, j, len;

    len = strlen(p);

    for(i=0; i<len; i++) {
        printf("%*c ", len-i, p[len-i-1]);
        for(j=len-i; j<=len; j++) printf("%c ",p[j]);
        printf("\r\n");
    }
}

int main(int argc, char **argv) {

    argc > 1 ? pyramid(argv[1]) :  ;
    pyramid("hoge");
    pyramid("abracadabra");
    return 0;
}

工夫すればもう少し簡潔に書けそうですが、表示速度が遅い点に目をつぶれば、ひとまず
目的は達したと言えそうです。(引数に半角空白が含まれる場合には対応していません。)

  e.g.
    C:\>pyramid abracadabra
              a
             r a
            b r a
           a b r a
          d a b r a
         a d a b r a
        c a d a b r a
       a c a d a b r a
      r a c a d a b r a
     b r a c a d a b r a
    a b r a c a d a b r a

遅延環境変数展開を利用しているので、Windows NTでは動作しません。Windows XPで動作
を確認。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
:: pyramid.bat
@echo off
  setlocal enabledelayedexpansion
    set l=0
    set n=0
    set s=
    set t=

    if "%1" == "" (echo %~n0 [STRING] & goto :EOF)

    call :length %1 l

    for /l %%i in (1,1,%l%) do (
      set s=
      set /a n=%l%-%%i
      for /l %%j in (!n!,-1,1) do set s=!s! 
      for /l %%j in (%%i,-1,1) do (
        set /a n=%l%-%%j
        call :substr %1 !n! 1 t
        set s=!s!!t!
        if %%j gtr 0 set s=!s! 
      )
      echo !s!
    )
  endlocal
goto :EOF

:length
  setlocal
    set i=0
    set t=%1
    set t=%t:"=%

    :loop
      set t=%t:~1%
      set /a i+=1
    if not "%t%" == "" goto loop
  endlocal & set %2=%i%
goto :EOF

:substr
  setlocal enabledelayedexpansion
    set t=%1
    set t=!t:~%2,%3!
  endlocal & set %4=%t%
goto :EOF

なんか美しくないですが...

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
%!PS

/pyramid { % (string) pyramid -
    dup length 1 sub dup -1 0 {
        dup { ( ) print } repeat
        1 2 index {
            2 index exch 1 getinterval print ( ) print
        } for
        ( ) =
    } for
} def

% ------- Test Code -------- 
(hoge) pyramid
(abracadabra) pyramid

あらかじめ最下段の文字列を作っておいてから、
オシリからアタマへ向かって表示部分を伸ばしつつ、
各行を printf で表示しています。
実行例:
$ ./pyramid hoge
   e
  g e
 o g e
h o g e
$ ./pyramid abracadabra
          a
         r a
        b r a
       a b r a
      d a b r a
     a d a b r a
    c a d a b r a
   a c a d a b r a
  r a c a d a b r a
 b r a c a d a b r a
a b r a c a d a b r a
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv){
    int i, len;
    char *srcstr, *cpstr, *s, *d, format[15];
    
    if(argc < 2) exit(1);
    srcstr = argv[1];
    len = strlen(srcstr);

    cpstr = malloc(len * 2);
    if(!cpstr) exit(1);

    s = srcstr + len - 1;
    d = cpstr + len * 2;
    *d-- = '\0';
    while(s != srcstr){
        *d-- = *s--;
        *d-- = ' ';
    }
    *d = *s;

    d = cpstr + len * 2 - 1;
    for(i = 0; i < len; i++, d -= 2){
        sprintf(format, "%%%ds\n", len + i);
        printf(format, d);
    }

    free(cpstr);
    return 0;
}

対象文字列はテンプレートパラメタ txt で渡してください。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<xsl:stylesheet version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:fn="http://www.w3.org/2005/xpath-functions"
  >

  <xsl:param name="txt" as="xs:string" />

  <xsl:output method="text" />

  <xsl:template match="/" >
    <xsl:variable name="chars" as="xs:string*">
      <xsl:for-each select="fn:string-to-codepoints($txt)">
        <xsl:sequence select="fn:codepoints-to-string((.))" />
      </xsl:for-each>
    </xsl:variable>

    <xsl:for-each select="1 to fn:count($chars)">
      <xsl:variable name="wscount" as="xs:integer"
        select="fn:count($chars)-." />
      <xsl:for-each select="1 to $wscount" >
        <xsl:text> </xsl:text>
      </xsl:for-each>
      <xsl:value-of select="fn:subsequence($chars, $wscount+1)" />
      <xsl:text>&#xA;</xsl:text>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

今更ですが。追加のモジュールを使わずに。

1
2
3
4
5
6
7
8
9
pyramid s =
  take ln $ [(replicate (ln - l) ' ') ++ (drop ((ln - l) * 2) ss) | l <- [1..]]
    where
      ln = length s
      ss = concat [[x,' '] | x <- s]

main = do
  mapM_ putStrLn $ pyramid "hoge"
  mapM_ putStrLn $ pyramid "abracadabra"

Whitespaceで。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
                   
    
                           
    
                     
    
                           
    
                        
    
              
    
                           
    
                        
    
                        
    
                        
    
                           
    
                           
    
                       
    
              
    
      

   
 
  
     
                              
          
         
       
       
 
 

      
 
     
         
           
       
           
 
                 
 
 
          
 
 
              

 
         

           




       
 
              
 
           
    
  
          
       
        
              
 
           
            
    
      
  
 
        

        
             
    
   

 


    

              
 
 
            
            
    
         
          
 
            

         
 


    
.

SQL Server 2008 で確認しました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
WITH
  Input(id, str) AS (
    SELECT 1, 'hoge'
    UNION ALL SELECT 2, 'abracadabra'
  )
, ExpandsSrc(id, str, input_str) AS (
    SELECT
        id
      , CAST(LEFT(str, 1) + ' ' AS varchar(max))
      , SUBSTRING(str, 2, LEN(str))
    FROM
        Input
    UNION ALL
    SELECT
        id
      , str + LEFT(input_str, 1) + ' '
      , SUBSTRING(input_str, 2, LEN(input_str))
    FROM
        ExpandsSrc
    WHERE
        input_str <> ''
  )
, Expands(id, str) AS (
    SELECT id, str FROM ExpandsSrc WHERE input_str = ''
  )
, Pyramid(id, i, str, input_str) AS (
    SELECT
        id
      , 1
      , str
      , SUBSTRING(str, 3, LEN(str))
    FROM
        Expands
    UNION ALL
    SELECT
        id
      , i + 1
      , SPACE(i) + input_str
      , SUBSTRING(input_str, 3, LEN(input_str))
    FROM
        Pyramid
    WHERE
        input_str <> ''
  )
SELECT str FROM Pyramid
ORDER BY id, i DESC

凡庸な解でして・・・

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
object MojiPira {
  def main(args : Array[String]) : Unit = {
    val moji = args(0)
    val m    = moji.length
    
    val fn = (m:Int,x:String) => println( x+" "*( 2*m - 1 - x.length ) )
    mojiPira(m).foreach(fn(m,_))
    
    def mojiPira(n:Int) :List[String] = {
      if( n==1 ){
        return List(moji(0).toString)
      }else{
        val tail = moji(n-1)
        val prev = mojiPira(n-1)
        var now = List(" "*prev.length + tail)
        for(a<-prev) now = now ::: (a + " " + tail)::Nil
        return now
      }
      Nil
    }
    
    ()
  }
}

文字列をリストに変換せずにやってみた。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
object MojiPira {
  def main(args : Array[String]) : Unit = {
    pyramid(args(0))
  }
  def pyramid(moji:String) = {
    val m    = moji.length
    mojiPira(" "*(m-1),"",moji.reverse){print _}
  }
  def mojiPira(mergin:String,prevPrn:String,s:String)(prn:String=>Unit) : Unit = {
      val prnStr = if (prevPrn=="") ""+s(0) else s(0) + " " + prevPrn
      prn(mergin + prnStr + mergin + "\n")
      if( mergin!="" )
        mojiPira(mergin.substring(1),prnStr,s.substring(1))(prn)
  }
}

ワンライナー系として。

1
"abracadabra".inject([]){r,i->[' '*r.size()+i]+r.collect{it+' '+i}}.each{println it}

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
using System;
using System.Linq;

namespace Sample {
    class Program {
        static void Main(string[] args) {
            Pyramid("hoge");
            Pyramid("abracadabra");
            Console.ReadLine();
        }

        static void Pyramid(string s) {
            int length = s.Length;
            for (int n = 0; n < length; n++) {
                // 左側の空白を表示
                int spCount = length - n - 1;
                Console.Write(new string(' ', spCount));
                // 右側の文字部分を表示
                var ls = s.Skip(spCount);
                foreach (var c in ls)
                    Console.Write(c + " ");
                Console.WriteLine();
            }
        }
    }
}

Index

Feed

Other

Link

Pathtraq

loading...