Head And Tail

November 13, 2015

Today’s exercise is a simple file-handling task for beginning programmers: take the name of a text file as input and write as output the first and last lines of the file.

Your task is to write the file-handling program described above. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

Pages: 1 2

11 Responses to “Head And Tail”

  1. FA said

    Scala with iterator

      def headAndTail(in: String) = {
        val lines = Source.fromFile(in).getLines()
        println(lines.next())
        while (lines.hasNext) {
          val last = lines.next
          if (!lines.hasNext) println(last)
        }
      }   
    
  2. Francesco said

    Haskell:

    (\x -> [head x, last x]) . lines <$> readFile "file.txt"
  3. klettier said

    FSharp :

    let writeLastAndFirstLines = fun x -> File.ReadAllLines(x) >> fun x -> (Array.head x, Array.last x) >> fun x -> printfn "%s\n%s" (fst x) (snd x)
    
    "test.txt" |> writeLastAndFirstLines
    
  4. wert310 said

    Haskell:

    headTail filename = (liftM lines $ readFile filename) >>=
                        mapM_ putStrLn . (zipWith ($) [head,last]) . repeat
    
  5. John Cowan said

    head -1 $1; tail -1 $1

  6. Jussi Piitulainen said

    I memory-mapped the file as a byte array. I wanted to learn about that.

    A source says it is guaranteed that an ASCII byte cannot occur in the middle of a UTF-8 character; other assumptions about what line-end characters occur where in the file remain because I couldn’t be bothered.

    # tiedoston ht.jl ensimmäinen rivi
    
    """Displays the first and last line of the named file, assuming way
       too much about the byte-level contents of the files."""
    
    function peek(name)
        s = Mmap.mmap(name, Array{UInt8,1}, filesize(name))
        print("head: ", utf8(s[1:findfirst(s, 0x0a)]))
        print("tail: ", utf8(s[findprev(s, 0x0a, end - 1) + 1:end]))
    end
    
    peek(ARGS[1])
    
    # tiedoston ht.jl viimeinen rivi
    

    Testing with the source code file itself:

    $ julia ht.jl ht.jl
    head: # tiedoston ht.jl ensimmäinen rivi
    tail: # tiedoston ht.jl viimeinen rivi
    $ 
    
  7. Sia said

    // C#:
    string[] lines = File.ReadAllLines(@”file.txt”);
    if (lines.Length != 0)
    {
    MessageBox.Show(lines[0] + “\n” + lines[lines.Length – 1]);
    }

  8. matthew said

    Here’s a C++ solution that just uses some basic Unix system functions – sbrk and brk for memory allocation, read and write for I/0. Probably should check return codes & allow for partial writes. Could be more intelligent about copying data from the input buffer too.

    #include <unistd.h>
    #include <fcntl.h>
    
    static const size_t BSIZE = 256;
    
    int main(int argc, char *argv[]) {
      int fd = (argc == 1) ? 0 : open(argv[1], O_RDONLY);
      char *buff = (char*)sbrk(2*BSIZE); // Allocate
      char *start = buff + BSIZE, *end = start + BSIZE;
      char *p = start;
      bool first = true;
      while (true) {
        ssize_t n = read(fd,buff,BSIZE);
        if (n <= 0) break;
        for (ssize_t i = 0; i < n; i++) {
          if (p > start && *(p-1) == '\n') {
            if (first) write(1,start,p-start);
            first = false;
            p = start;
          }
          if (p == end) brk(end += BSIZE); // Extend
          *p++ = buff[i];
        }
      }
      write(1,start,p-start);
    }
    
  9. ;; A Simple Clisp solution

    (defun head-tail(name)
    (let (last)
    (with-open-file (file name)
    (print (read-line file))
    (loop for x = (read-line file nil) while x do
    (setf last x))
    (print last))))

  10. fisherro said

    Using the Reverse_file_buf from my solution to the 17 November 2015 exercise…

    It’s pretty fast even on large files (despite the inefficiencies of Reverse_file_buf) because it jumps straight to the end to find the last line.

    #include <algorithm>
    #include <cctype>
    #include <fstream>
    #include <iostream>
    #include <string>
    #include <vector>
    #include "Reverse_file_buf.hpp"
    
    //Ignores lines with only whitespace or control characters.
    //Not Unicode friendly.
    std::string find_first_line(std::istream& in)
    {
        std::string line;
        while (std::getline(in, line)) {
            if (std::any_of(line.begin(), line.end(), ::isgraph)) {
                return line;
                break;
            }
        }
        return "";
    }
    
    int main(int argc, char** argv)
    {
        std::vector<std::string> args(argv + 1, argv + argc);
        if (args.empty()) args.push_back("praxis.cpp");
        for (auto arg: args) {
            std::ifstream forwards(arg);
            std::cout << find_first_line(forwards) << '\n';
            Reverse_file_buf rfb(arg);
            std::istream backwards(&rfb);
            auto line = find_first_line(backwards);
            std::reverse(line.begin(), line.end());
            std::cout << line << '\n';
        }
    }
    
  11. r. clayton said

    Some Racket Scheme solutions .

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: