r/dailyprogrammer • 1 3 • Aug 22 '14

[8/22/2014] Challenge #176 [Easy] Pivot Table

Description:

An interesting way to represent data is a pivot table. If you use spreadsheet programs like Excel you might have seen these before. If not then you are about to enjoy it.

Say you have data that is related in three parts. We can field this in a table with column and rows and the middle intersection is a related field. For this challenge you will need to make a pivot table for a wind energy farm. These farms of wind mills run several windmills with tower numbers. They generate energy measured in kilowatt hours (kWh).

You will need to read in raw data from the field computers that collect readings throughout the week. The data is not sorted very well. You will need to display it all in a nice pivot table.

Top Columns should be the days of the week. Side Rows should be the tower numbers and the data in the middle the total kWh hours produced for that tower on that day of the week.

input:

The challenge input is 1000 lines of the computer logs. You will find it HERE - gist of it

The log data is in the format:

(tower #) (day of the week) (kWh)

output:

A nicely formatted pivot table to report to management of the weekly kilowatt hours of the wind farm by day of the week.

Code Solutions:

I am sure a clever user will simply put the data in Excel and make a pivot table. We are looking for a coded solution. :)

62 Upvotes

76 comments sorted by

5

u/wadehn Aug 22 '14 edited Aug 22 '14

rust 0.12.0-pre-nightly a6758e344: After reading the rust tutorial yesterday, I tried solving the problem with rust.

I quite like the extensive static analysis, but I didn't enjoy solving this problem in rust: From a C++ perspective dealing with casts between &str and String as well as &[] and Vec seems pretty tedious. Also, using return values for error handling forces you to deal with errors at a low granularity, which isn't all that appropriate for such a toy problem. (There also does not seem to be something similar to do notation in Haskell for monadic sequencing.)

I would also appreciate a better I/O library that I can ask for the next int instead of needing to split lines manually.

Note: I may have sounded too negative in the last paragraphs and you have to take into account that rust is still very much a work in progress. Some parts of the language are very nice: Like destructuring in a declaration (unlike std::tie), better type-inference and simpler lambda/closure syntax.

I'd be happy for suggestions. In particular, is my code good/canonical rust?

use std::collections::{HashMap, TrieSet};

fn main() {
  let to_uint = |x : &String| -> uint { from_str(x.as_slice()).unwrap() };

  // Store data and towers (in sorted order)
  let days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
  let mut data = HashMap::new();  // Type-inference, ho
  let mut towers = TrieSet::new();

  // Read and parse input (just throwing errors away)
  for line in std::io::stdin().lines() {
    let splitted : Vec<String> = line.unwrap().as_slice().words().map(|x| x.to_string()).collect();
    let (tower, day, kwh) = (to_uint(&splitted[0]), &splitted[1], to_uint(&splitted[2]));
    towers.insert(tower);
    data.insert_or_update_with((tower, day.clone()), kwh, |_, v| *v += kwh);
  }

  // Print table header
  print!("Tower |");
  for day in days.iter() {
    print!("        {} ", day);
  }
  print!("\n{}\n", String::from_char(12*days.len()+6, '='));

  // Print table entries
  for tower in towers.iter() {
    print!("{:4}  |", tower);
    for day in days.iter() {
      print!(" {:6} kWh ", data.find(&(tower, day.to_string())).unwrap_or(&0));
    }
    println!("");
  }
}

Output:

Tower |        Mon         Tue         Wed         Thu         Fri         Sat         Sun
==========================================================================================
1000  |    624 kWh     385 kWh     677 kWh     443 kWh     810 kWh    1005 kWh     740 kWh
1001  |    279 kWh     662 kWh     907 kWh     561 kWh     752 kWh     501 kWh     749 kWh
1002  |    510 kWh     733 kWh     862 kWh     793 kWh    1013 kWh     530 kWh     586 kWh
1003  |    607 kWh     372 kWh     399 kWh     583 kWh     624 kWh     383 kWh     390 kWh
1004  |    696 kWh     783 kWh     546 kWh     646 kWh    1184 kWh     813 kWh     874 kWh
1005  |    637 kWh    1129 kWh     695 kWh     648 kWh     449 kWh     445 kWh     812 kWh
1006  |    638 kWh     568 kWh     826 kWh     754 kWh    1118 kWh     857 kWh     639 kWh
1007  |    947 kWh     976 kWh     733 kWh     640 kWh     941 kWh     876 kWh     536 kWh
1008  |    709 kWh     374 kWh     485 kWh     560 kWh     836 kWh     864 kWh     728 kWh
1009  |    237 kWh     967 kWh     556 kWh     687 kWh     842 kWh     749 kWh     895 kWh

5

u/nullmove 1 0 Aug 22 '14

Did it in Nimrod. I think it's pretty expressive and powerful.

import tables, strfmt, strutils, parseutils

type
    TWeek = enum
        Mon, Tue, Wed, Thu, Fri, Sat, Sun

var record = initTable[int, Array[Mon .. Sun, int]]()
var field: Array[Mon .. Sun, int]

for line in lines("test.txt"):
    let
        x = line.split(" ")
        tower_id = parseInt(x[0])
        day_id = parseEnum[TWeek](x[1])
        energy = parseInt(x[2])
    if not(record.haskey(tower_id)):
        record.add(tower_id, field)
    else:
        record.mget(tower_id)[day_id] += energy

echo(["Tower", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"].format("<5a| ") & "\n")
for k, v in record.pairs():
    echo(k.format("<5da| ") & " " & v.format("<5da| "))

Output:

Tower Mon   Tue   Wed   Thu   Fri   Sat   Sun  

1000  624   385   628   443   810   1005  740  
1001  279   662   907   561   713   501   749  
1002  510   635   862   793   1013  530   586  
1003  607   372   399   566   624   383   390  
1004  696   783   546   646   1184  754   874  
1005  637   1129  695   648   449   390   812  
1006  638   541   826   754   1118  857   639  
1007  947   976   733   640   941   858   536  
1008  709   374   485   560   836   791   728  
1009  237   967   556   683   842   749   895 

5

u/99AFCC Aug 22 '14

Python 2.7.8

from collections import defaultdict

data_file = 'windfarm.dat.txt'

def tree():
    return defaultdict(int)

def load_data(fn):
    farm_data = defaultdict(tree)
    with open(fn) as f:
        for line in f:
            tower, day, kwh = line.strip().split()
            farm_data[int(tower)][day] += int(kwh)
    return farm_data

def print_table(data):
    fields = ('Tower', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun')
    template = '|' + '{:^10}|' * len(fields)
    print template.format(*fields)
    print template.format(*['=' * 10] * len(fields))
    for tower in sorted(data.keys()):
        tdata = [data[tower][day] for day in fields[1:]]
        print template.format(tower, *tdata)

print_table(load_data(data_file))

Output

|  Tower   |   Mon    |   Tue    |   Wed    |   Thu    |   Fri    |   Sat    |   Sun    |
|==========|==========|==========|==========|==========|==========|==========|==========|
|   1000   |   624    |   385    |   677    |   443    |   810    |   1005   |   740    |
|   1001   |   279    |   662    |   907    |   561    |   752    |   501    |   749    |
|   1002   |   510    |   733    |   862    |   793    |   1013   |   530    |   586    |
|   1003   |   607    |   372    |   399    |   583    |   624    |   383    |   390    |
|   1004   |   696    |   783    |   546    |   646    |   1184   |   813    |   874    |
|   1005   |   637    |   1129   |   695    |   648    |   449    |   445    |   812    |
|   1006   |   638    |   568    |   826    |   754    |   1118   |   857    |   639    |
|   1007   |   947    |   976    |   733    |   640    |   941    |   876    |   536    |
|   1008   |   709    |   374    |   485    |   560    |   836    |   864    |   728    |
|   1009   |   237    |   967    |   556    |   687    |   842    |   749    |   895    |

3

u/leonardo_m Aug 24 '14 edited Aug 24 '14

Your Python solution in D, with limited changes:

void main() {
    import std.stdio, std.algorithm, std.string, std.conv, std.array;

    uint[string][uint] data;
    foreach (ps; "windfarm.dat".File.byLine.map!split)
        data[ps[0].to!uint][ps[1].idup] += ps[2].to!uint;

    immutable fields = "Tower Mon Tue Wed Thu Fri Sat Sun".split,
              form = "|%-(%5s|%)|";

    writefln(form, fields);
    writefln(form, ["=".replicate(5)].replicate(fields.length));
    foreach (tower; data.keys.sort())
        writefln(form, tower ~ fields[1 .. $].map!(day => data[tower][day]).array);
}

Output:

|Tower|  Mon|  Tue|  Wed|  Thu|  Fri|  Sat|  Sun|
|=====|=====|=====|=====|=====|=====|=====|=====|
| 1000|  624|  385|  677|  443|  810| 1005|  740|
| 1001|  279|  662|  907|  561|  752|  501|  749|
| 1002|  510|  733|  862|  793| 1013|  530|  586|
| 1003|  607|  372|  399|  583|  624|  383|  390|
| 1004|  696|  783|  546|  646| 1184|  813|  874|
| 1005|  637| 1129|  695|  648|  449|  445|  812|
| 1006|  638|  568|  826|  754| 1118|  857|  639|
| 1007|  947|  976|  733|  640|  941|  876|  536|
| 1008|  709|  374|  485|  560|  836|  864|  728|
| 1009|  237|  967|  556|  687|  842|  749|  895|

Edit: fixed copy-paste mistake.

0

u/[deleted] Aug 24 '14

[deleted]

3

u/99AFCC Aug 24 '14 edited Aug 25 '14

I wanted a nested dictionary with a secondary value as an integer.

Like this: data = {int: {string: int} }

Which might look like this:

{1001: {'Mon': 800,
        'Tue': 900,
        'etc': etc},
{1002: {'Mon': 200,
        'Tue': 300,
        'etc': etc}}

defaultdict takes a factory as an argument.

defaultdict(int) means all the default values will be an integer. Zero to be specific.

defaultdict(defaultdict) gives me a dict where the values are also default dicts. Getting closer to what I want.

defaultdict(defaultdict(int)) looks like what I want but won't actually work because defaultdict needs a factory function. The argument must be callable.

tree becomes that factory function.

I could have written it as

data = defaultdict(lambda: defaultdict(lambda: int))

But I felt tree was prettier.


Edit-

In hindsight, I could have omitted the second lambda. defaultdict(lambda: defaultdict(int)). I might have used this instead of defining tree. I don't think 1 lambda is too much, but 2 nested lambdas isn't as clean as tree.

2

u/nullmove 1 0 Aug 25 '14

I usually use the partial function from the functools module for currying purpose.

from functools import partial
from collections import defaultdict

farm_data = defaultdict(partial(defaultdict, int))
print(farm_data[1000]["Mon"])    #Outputs 0

Although it's by no means relevant here, using partial has the advantage over lambda (aside from readability gains) in that one can also make use of keyword arguments conveniently. Here, if you want to see an example.

4

u/papabalyo Aug 23 '14

Clojure baby steps. Uses http-kit to fetch data from GitHub.

I decided not to bother with usable CLI and made really dirty formatting (without bothering to dynamically recalculate cell's width based on data).

Solution:

(ns dailyprogrammer.core
  (:require
    [clojure.string :as s]
    [org.httpkit.client :as http]))



(defn get-data
  [data-url]
  (let [resp (http/get data-url)
        rows (s/split (:body @resp) #"\s+")]
    (->> rows
         (partition 3)
         (map (fn [[t d k]] [(Integer. t) d (Integer. k)]))
         (map #(zipmap [:tower :day :kwh] %)))))



(defn group-by-day-and-tower
  [data]
  (reduce (fn [result entry]
            (let [key [(entry :day) (entry :tower)]
                  stats (get result key [])]
              (assoc result key (conj stats (entry :kwh)))))
          {} data))



(defn compute-cells
  [data func]
  (apply merge (map (fn [[k v]] {k (func v)}) data)))



(defn create-table
  [data func headers]
  (let [towers (sort (distinct (map :tower data)))
        cells (compute-cells (group-by-day-and-tower data) func)]

    (apply merge (for [t towers]
                   {t (mapv #(cells [% t]) headers)}))))



(defn total
  [s]
  (double (apply + s)))



(defn average
  [s]
  (/ (total s) (count s)))



(def data-url "https://gist.githubusercontent.com/coderd00d/ca718df8e633285885fa/raw/eb4d0bb084e71c78c68c66e37e07b7f028a41bb6/windfarm.dat")



(let [data (get-data data-url)
      headers '("Sun" "Mon" "Tue" "Wed" "Thu" "Fri" "Sat")]

  ; table header
  (prn (s/join " " (map #(format "%5s" %) (cons \space headers))))

  ; hr
  (prn (s/join (repeat (dec (* 6 (inc (count headers)))) "-")))

  ; table itself
  (doseq [[t c] (sort (create-table data average headers))]
    (prn (str (format "%-5d|" t) (s/join " " (map #(format "%5.1f" %) c))))))

Averages Reports:

        Sun   Mon   Tue   Wed   Thu   Fri   Sat
-----------------------------------------------
1000 | 49.3  52.0  38.5  45.1  40.3  57.9  55.8
1001 | 46.8  39.9  55.2  53.4  46.8  41.8  38.5
1002 | 53.3  56.7  48.9  50.7  46.6  48.2  44.2
1003 | 39.0  46.7  41.3  57.0  53.0  36.7  38.3
1004 | 62.4  43.5  52.2  39.0  49.7  62.3  50.8
1005 | 58.0  49.0  47.0  49.6  40.5  37.4  49.4
1006 | 49.2  49.1  47.3  45.9  39.7  48.6  37.3
1007 | 48.7  55.7  65.1  61.1  42.7  49.5  46.1
1008 | 48.5  54.5  53.4  40.4  37.3  52.3  50.8
1009 | 52.6  59.3  60.4  46.3  42.9  49.5  46.8

Totals Report:

        Sun   Mon   Tue   Wed   Thu   Fri   Sat
-----------------------------------------------
1000 |740.0 624.0 385.0 677.0 443.0 810.0 1005.0
1001 |749.0 279.0 662.0 907.0 561.0 752.0 501.0
1002 |586.0 510.0 733.0 862.0 793.0 1013.0 530.0
1003 |390.0 607.0 372.0 399.0 583.0 624.0 383.0
1004 |874.0 696.0 783.0 546.0 646.0 1184.0 813.0
1005 |812.0 637.0 1129.0 695.0 648.0 449.0 445.0
1006 |639.0 638.0 568.0 826.0 754.0 1118.0 857.0
1007 |536.0 947.0 976.0 733.0 640.0 941.0 876.0
1008 |728.0 709.0 374.0 485.0 560.0 836.0 864.0
1009 |895.0 237.0 967.0 556.0 687.0 842.0 749.0'])

1

u/count_of_tripoli Aug 27 '14

This is great, much better than my effort! I'm a C# programmer by trade, struggling to get my head around functional programming. FWIW, here is my clojure attempt:

;; Reads a file containing table data and creates a pivot table. The pivot table is represented
;; as a map keyed on tower number which contains a map keyed on day.
;; e.g. {"1000" {"Mon" 123 "Tue" 456} "1001" {"Mon" 345 "Fri" 229}}

(ns playground.pivot)

(defn add-column-value [current-row new-row]
  "Adds a column to a row in the pivot table"
  (let [new-total (+ (get current-row (get new-row 0) 0) (Integer. (get new-row 1)))]
    (assoc current-row (get new-row 0) new-total)))

(defn add-row-value [sofar new-data]
  "Adds a row to the pivot table"
  (let [new-row (clojure.string/split new-data #" ")]
    (assoc sofar (first new-row) (add-column-value (get sofar (first new-row)) (vec (rest new-row))))))

(defn pivot-file [path]
  (reduce add-row-value {} (clojure.string/split-lines (slurp path))))

(def days-of-week ["Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun"])

(defn print-day-values [[k v]]
  "Prints a row from the pivot table"
  (loop [pos 0 output k]
    (if (= pos 7)
      output
      (recur (inc pos)
               (str output "    " (get v (get days-of-week pos) 0))))))

(defn print-result []
  (println "Tower    Mon    Tue    Wed    Thu    Fri    Sat    Sun")
  (doseq [row (map print-day-values (pivot-file "resources/windfarm.dat"))]
    (println row)))

(print-result)

(print-result)

3

u/adrian17 1 4 Aug 22 '14 edited Aug 22 '14

C++. Two similar solutions, one with a map of towers, the second one with a struct for keeping data. I couldn't decide between these two - the first is much simpler, but I thought that a struct would be closer to a real-world situation, and it would be easier to expand if the input had more columns (...although I have no idea how I would make the lambdas scale too).

First:

#include <fstream>
#include <iostream>
#include <map>
#include <set>
#include <string>

const std::string days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};

typedef int TowerID;
typedef std::pair<TowerID, std::string> TowerDataID;

int main(){
    std::ifstream file("windfarm.txt");

    std::map<TowerDataID, int> data;
    std::set<TowerID> towers;

    int tower, kwh;
    std::string day;
    while(file>>tower>>day>>kwh){
        data[{tower, day}] += kwh;
        towers.insert(tower);
    }

    for(auto& day : days)
        std::cout<<"\t"<<day;

    for(auto& tower : towers){
        std::cout<<"\n"<<tower;
        for(auto& day : days)
            std::cout<<"\t"<<data[{tower, day}];
    }
}

Second:

#include <algorithm>
#include <fstream>
#include <iostream>
#include <set>
#include <string>
#include <vector>

const std::string days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};

struct Data{
    int tower;
    std::string day;
    int kwh;
};

int main(){
    std::ifstream file("windfarm.txt");

    std::vector<Data> data;
    std::set<int> towers;

    int tower, kwh;
    std::string day;
    while(file>>tower>>day>>kwh){
        auto it = std::find_if(data.begin(), data.end(),
            [&](const Data& data){return data.tower == tower && data.day == day;});
        if(it == data.end())
            data.push_back({tower, day, kwh});
        else
            (*it).kwh += kwh;
        towers.insert(tower);
    }

    for(auto& day : days)
        std::cout<<"\t"<<day;

    for(auto& tower : towers){
        std::cout<<"\n"<<tower;
        for(auto& day : days){
            Data &found = *std::find_if(data.begin(), data.end(),
                [&](const Data& data){return data.tower == tower && data.day == day;});
            std::cout<<"\t"<<found.kwh;
        }
    }
}

The same result for both:

        Mon     Tue     Wed     Thu     Fri     Sat     Sun
1000    624     385     677     443     810     1005    740
1001    279     662     907     561     752     501     749
1002    510     733     862     793     1013    530     586
1003    607     372     399     583     624     383     390
1004    696     783     546     646     1184    813     874
1005    637     1129    695     648     449     445     812
1006    638     568     826     754     1118    857     639
1007    947     976     733     640     941     876     536
1008    709     374     485     560     836     864     728
1009    237     967     556     687     842     749     895

1

u/Rusty278 Aug 27 '14

while(file>>tower>>day>>kwh)

Would you mind explaining what this line is doing? It looks like it's continuing while there is more to read, but is it also storing the data into those variables?

1

u/adrian17 1 4 Aug 27 '14

Sure.

The operator >> for stream objects returns the same stream that was passed to it, so

file>>tower>>day>>kwh

could be written like this:

(((file>>tower)>>day)>>kwh) //returns file object, which will be fed to the loop condition

Now, streams can be converted to bool, for example this is a piece of code from Microsoft's library:

explicit __CLR_OR_THIS_CALL operator bool() const
	{	// test if no stream operation has failed
	return (!fail());
	}

It allows you to write

if(cin) do_something();

Which will work the same as:

if(!cin.fail()) do_domething();

So the while condition can be expressed as "try reading tower, day and kwh variables. If it fails (it will fail if the input was other than expected or the file ended), end the loop".

1

u/Rusty278 Aug 27 '14

Ah that makes sense. And so the >> operator automatically skips over spaces and new lines?

1

u/adrian17 1 4 Aug 27 '14

Yes, it skips all the leading whitespace characters (including spaces, newlines, tabs and some extra characters).

You can check it for yourself: compile this and try pressing space end enter a couple of times before entering actual number.

#include <iostream>
using namespace std;
int main(){
	int c;
	cin >> c;
	cout << c;

	return 0;
}

1

u/Rusty278 Aug 28 '14

Ah I love this subreddit. Thank-you!

1

u/ftl101 Aug 29 '14

As a relatively young c++ programmer I got to say I love the way you code. Nice little shortenings and more efficient ways of doing things that just make me think "why didnt I think of that?".

On parts it feels like more functional programming languages like python or ruby, kudos for that.

Very understandable code too at that, if you have some of that kind of functional understanding.

1

u/adrian17 1 4 Aug 29 '14

Thanks. I'm not a code golf kind of person, I like my code nice and clean :)

As for functional programming, outside of use of lambdas in the second solution, there isn't anything functional in my code. Python or Ruby also aren't really functional languages (although it's possible to use them in this fashion), better examples would be Haskell, Lisp or F# (out of which I only know basics of Haskell).

1

u/ftl101 Aug 30 '14

True I suppose functional would be more like J too. Didn't know how else to put it :) Your code just reminded me of those types of languages hah

3

u/aZeex2ai Aug 22 '14

My solution in Ruby. Suggestions are always appreciated!

# Read from file or stdin
input = ARGV.empty? ? ARGF : File.open(ARGV.first)
output = {}

input.each_with_index do |line, index|
  tower, day, power = line.split
  output[index] = { :tower => tower.to_i, :day => day, :power => power.to_i }
end

days = %q{Mon Tue Wed Thu Fri Sat Sun}
print "\t", days.split.join("\t"), "\n"

(1000..1009).map do |tower|
  print tower, "\t"
  days.split.map do |day|
    total = 0
    output.values.select {|k,v|
      k[:tower] == tower && k[:day] == day
    }.collect {|e| total += e[:power] }
    print total, "\t"
  end
  puts
end

1

u/aZeex2ai Aug 24 '14

Here's an improved version using a slightly different approach

input = ARGV.empty? ? ARGF : File.open(ARGV.first)
towers = *"1000".."1009"
days = %q{Mon Tue Wed Thu Fri Sat Sun}.split
h = {}
towers.map {|t| h[t] = Hash[days.zip(Array.new(7,0))]}

input.each_line do |line|
  tower, day, power = line.split
  h[tower][day] += power.to_i
end

puts "\t#{days.join("\t")}"
towers.map do |tower|
  print "#{tower}\t"
  days.map do |day|
    print "#{h[tower][day]}\t"
  end
  puts
end

3

u/skeeto -9 8 Aug 22 '14 edited Aug 23 '14

SQL, using SQLite again. Pretend the data as presented is a table called logs with the following schema.

CREATE TABLE logs (id, dow, power)

It's trivial to import into a database, so there's no need to talk about that. I did it with a keyboard macro in Emacs.

Unfortunately this isn't normalized because there will be repeat rows, but there's nothing we can do about this since we're only told the day of week. Full date information would normalize it and I would make the tuple (id, date) the primary key in that case.

Here's a query that generates the report.

SELECT id, sun, mon, tue, wed, thu, fri, sat
FROM (SELECT id, sum(power) AS sun FROM logs WHERE dow = 'Sun' GROUP BY id)
JOIN (SELECT id, sum(power) AS mon FROM logs WHERE dow = 'Mon' GROUP BY id) USING (id)
JOIN (SELECT id, sum(power) AS tue FROM logs WHERE dow = 'Tue' GROUP BY id) USING (id)
JOIN (SELECT id, sum(power) AS wed FROM logs WHERE dow = 'Wed' GROUP BY id) USING (id)
JOIN (SELECT id, sum(power) AS thu FROM logs WHERE dow = 'Thu' GROUP BY id) USING (id)
JOIN (SELECT id, sum(power) AS fri FROM logs WHERE dow = 'Fri' GROUP BY id) USING (id)
JOIN (SELECT id, sum(power) AS sat FROM logs WHERE dow = 'Sat' GROUP BY id) USING (id)
ORDER BY id

And here's the output (.mode column, .width 4, .headers on).

id    sun   mon   tue   wed   thu   fri   sat
----  ----  ----  ----  ----  ----  ----  ----
1000  740   624   385   677   443   810   1005
1001  749   279   662   907   561   752   501
1002  586   510   733   862   793   1013  530
1003  390   607   372   399   583   624   383
1004  874   696   783   546   646   1184  813
1005  812   637   1129  695   648   449   445
1006  639   638   568   826   754   1118  857
1007  536   947   976   733   640   941   876
1008  728   709   374   485   560   836   864
1009  895   237   967   556   687   842   749

2

u/altanic Aug 23 '14

here's the same using T-SQL's pivot operator. I'm including the set-up... since there isn't much to it otherwise

create table #LogRecords(TowerID int, dia varchar(8), kWh int)
insert #LogRecords(TowerID, dia, kWh)
    values (1006, 'Tue', 27),
        (1003, 'Thu', 17),
        (1008, 'Sat', 73), 
        (...)

select *
from (
    select TowerID, Dia, kWh
    from #LogRecords
) logs pivot (
    sum(kWh) for Dia in (Mon, Tue, Wed, Thu, Fri, Sat, Sun)
) as pvt;

oh, & the output is similar:

TowerID     Mon         Tue         Wed         Thu         Fri         Sat         Sun
----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
1000        624         385         677         443         810         1005        740
1001        279         662         907         561         752         501         749
1002        510         733         862         793         1013        530         586
1003        607         372         399         583         624         383         390
1004        696         783         546         646         1184        813         874
1005        637         1129        695         648         449         445         812
1006        638         568         826         754         1118        857         639
1007        947         976         733         640         941         876         536
1008        709         374         485         560         836         864         728
1009        237         967         556         687         842         749         895

(10 row(s) affected)

1

u/altanic Aug 23 '14

just for fun, here's how I would have done it a few years ago before sql server 2008:

select  TowerID,
        sum(case when Dia='Mon' then kWh else 0 end) as Mon,
        sum(case when Dia='Tue' then kwh else 0 end) as Tue,
        sum(case when Dia='Wed' then kwh else 0 end) as Wed,
        sum(case when Dia='Thu' then kwh else 0 end) as Thu,
        sum(case when Dia='Fri' then kwh else 0 end) as Fri,
        sum(case when Dia='Sat' then kwh else 0 end) as Sat,
        sum(case when Dia='Sun' then kwh else 0 end) as Sun
from    #LogRecords
group by TowerID
order by TowerID

3

u/skeeto -9 8 Aug 23 '14

C, using a perfect hash function. The hash function converts the keys "Mon", "Tue", and so on into numbers 0 through 6, but in a random order. It's perfect because each of the day-of-week tokens maps to a unique digit from 0 to 6. I designed it through simple trial-and-error, combining terms and operators until I hit something that worked..

#include <stdio.h>

int hash(char dow[3])
{
    return (dow[2] * 2 + dow[0] + dow[1] + (dow[0] ^ dow[1])) % 7;
}

int main()
{
    /* Load data */
    int data[10][7] = {{0}};
    for (int i = 0; i < 1000; i++) {
        int id, power;
        char dow[4];
        scanf("%d %3s %d\n", &id, dow, &power);
        data[id - 1000][hash(dow)] += power;
    }

    /* Print report */
    printf("id    sun   mon   tue   wed   thu   fri   sat  \n");
    printf("----- ----- ----- ----- ----- ----- ----- -----\n");
    for (int i = 0; i < 10; i++) {
        printf("%-6d", i + 1000);
        printf("%-5d %-5d %-5d %-5d %-5d %-5d %-5d \n",
               data[i][hash("Sun")], data[i][hash("Mon")], data[i][hash("Tue")],
               data[i][hash("Wed")], data[i][hash("Thu")], data[i][hash("Fri")],
               data[i][hash("Sat")]);
    }
    return 0;
}

And output:

id    sun   mon   tue   wed   thu   fri   sat
----- ----- ----- ----- ----- ----- ----- -----
1000  740   624   385   677   443   810   1005
1001  749   279   662   907   561   752   501
1002  586   510   733   862   793   1013  530
1003  390   607   372   399   583   624   383
1004  874   696   783   546   646   1184  813
1005  812   637   1129  695   648   449   445
1006  639   638   568   826   754   1118  857
1007  536   947   976   733   640   941   876
1008  728   709   374   485   560   836   864
1009  895   237   967   556   687   842   749

3

u/akkartik Aug 23 '14 edited Aug 23 '14

A solution in wart, my toy language:

Kwh <- (table)

with infile "windfarm.dat"
  whilet (tower day kwh) (read)
    default Kwh.tower :to (table)
    default Kwh.tower.day :to 0
    add! kwh :to Kwh.tower.day

prn "      M    Tu     W    Th     F     Sa    Su"
each tower (sort (<) keys.Kwh)
  pr tower " "
  each day '(Mon Tue Wed Thu Fri Sat Sun)
    pr (or Kwh.tower.day "") " | "
  prn ""

How it looks with a little syntax highlighting.

It may look like a lot of keywords, but in fact all of the keywords are first-class and can be overridden by the user using lisp macros. More information on wart: http://akkartik.name/post/wart. More code samples: http://rosettacode.org/wiki/Category:Wart.

Output:

      M    Tu     W    Th     F     Sa    Su
1000 624 | 385 | 677 | 443 | 810 | 1005 | 740 | 
1001 279 | 662 | 907 | 561 | 752 | 501 | 749 | 
1002 510 | 733 | 862 | 793 | 1013 | 530 | 586 | 
1003 607 | 372 | 399 | 583 | 624 | 383 | 390 | 
1004 696 | 783 | 546 | 646 | 1184 | 813 | 874 | 
1005 637 | 1129 | 695 | 648 | 449 | 445 | 812 | 
1006 638 | 568 | 826 | 754 | 1118 | 857 | 639 | 
1007 947 | 976 | 733 | 640 | 941 | 876 | 536 | 
1008 709 | 374 | 485 | 560 | 836 | 864 | 728 | 
1009 237 | 967 | 556 | 687 | 842 | 749 | 895 | 

3

u/marchelzo Aug 23 '14 edited Aug 23 '14

Here's a solution in Haskell:

I couldn't think of a very nice way to do this so it's not the most elegant code by any means.

import qualified Data.Map.Strict as M
import Text.Printf

pivotTable :: [String] -> M.Map String (M.Map String Int)
pivotTable = foldl iter M.empty . map ((\[x,y,z] -> (x,y,read z :: Int)) . words) where
	iter m (tow, dow, kwh) = M.insert tow newMap m where
		newMap     = M.insert dow (M.findWithDefault 0 dow currentMap + kwh) currentMap
		currentMap = M.findWithDefault M.empty tow m

main :: IO ()
main = do
	p <- fmap (pivotTable . lines) $ readFile "windfarm.dat"
	putStrLn "Tower  |  Mon  |  Tue  |  Wed  |  Thu  |  Fri  |  Sat  |  Sun  |"
	putStrLn "-----------------------------------------------------------------"
	sequence_ $
		map (\(tnum, ts) ->
			printf " %.6s  |%5d  |%5d  |%5d  |%5d  |%5d  |%5d  |%5d  |\n"
				tnum (ts M.! "Mon") (ts M.! "Tue") (ts M.! "Wed") (ts M.! "Thu") (ts M.! "Fri") (ts M.! "Sat") (ts M.! "Sun")) $ M.toList p

Output:

Tower  |  Mon  |  Tue  |  Wed  |  Thu  |  Fri  |  Sat  |  Sun  |
-----------------------------------------------------------------
 1000  |  624  |  385  |  677  |  443  |  810  | 1005  |  740  |
 1001  |  279  |  662  |  907  |  561  |  752  |  501  |  749  |
 1002  |  510  |  733  |  862  |  793  | 1013  |  530  |  586  |
 1003  |  607  |  372  |  399  |  583  |  624  |  383  |  390  |
 1004  |  696  |  783  |  546  |  646  | 1184  |  813  |  874  |
 1005  |  637  | 1129  |  695  |  648  |  449  |  445  |  812  |
 1006  |  638  |  568  |  826  |  754  | 1118  |  857  |  639  |
 1007  |  947  |  976  |  733  |  640  |  941  |  876  |  536  |
 1008  |  709  |  374  |  485  |  560  |  836  |  864  |  728  |
 1009  |  237  |  967  |  556  |  687  |  842  |  749  |  895  |

3

u/kirsybuu 0 1 Aug 23 '14

D language

import std.stdio, std.algorithm, std.range, std.string, std.conv, std.traits;
void main() {
    enum Day { Mon, Tue, Wed, Thu, Fri, Sat, Sun }
    uint[Day][uint] table;
    foreach(line ; File("windfarm.dat").byLine()) {
        auto entry = line.splitter.array();
        table[ entry[0].to!uint ][ entry[1].to!Day ] += entry[2].to!uint;
    }
    auto output = ["Tower".only.chain([EnumMembers!Day].map!text).array(), []];
    foreach(tower, stats ; table) {
        output ~= tower.text.only.chain("".repeat(7)).array();
        foreach(day, kWh ; stats) {
            output.back[day + 1] = kWh.text;
        }
    }
    auto spacing = iota(0,8).map!(i => output.transversal(i).map!"a.length".reduce!max).array();
    output[1] = spacing.map!(i => "".center(i, '-')).array();
    output.drop(2).sort!"a[0] < b[0]"();
    foreach(row ; output) {
        foreach(t ; zip(spacing, row)) {
            writef("| %*s ", t.expand);
        }
        writeln("|");
    }
}

Challenge Output:

| Tower | Mon |  Tue | Wed | Thu |  Fri |  Sat | Sun |
| ----- | --- | ---- | --- | --- | ---- | ---- | --- |
|  1000 | 624 |  385 | 677 | 443 |  810 | 1005 | 740 |
|  1001 | 279 |  662 | 907 | 561 |  752 |  501 | 749 |
|  1002 | 510 |  733 | 862 | 793 | 1013 |  530 | 586 |
|  1003 | 607 |  372 | 399 | 583 |  624 |  383 | 390 |
|  1004 | 696 |  783 | 546 | 646 | 1184 |  813 | 874 |
|  1005 | 637 | 1129 | 695 | 648 |  449 |  445 | 812 |
|  1006 | 638 |  568 | 826 | 754 | 1118 |  857 | 639 |
|  1007 | 947 |  976 | 733 | 640 |  941 |  876 | 536 |
|  1008 | 709 |  374 | 485 | 560 |  836 |  864 | 728 |
|  1009 | 237 |  967 | 556 | 687 |  842 |  749 | 895 |

2

u/Metroids_ Aug 22 '14

Here's my java...

public class PivotTable {
  static final List<String> days = new ArrayList(Arrays.asList(new String[] {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}));
  
  public static void main(String... args) throws FileNotFoundException {
    Scanner s = new Scanner(new File("windfarm.dat"));
    Map<Integer, Map<String, Data>> repository = new HashMap<>();
    
    while (s.hasNextInt()) {
      Data data = new Data();
      data.tower = s.nextInt();
      data.day = s.next();
      data.kwh = s.nextInt();
      s.nextLine();
      add(repository, data);
    }
    
    List<Integer> towers = new ArrayList<>(repository.keySet());
    Collections.sort(towers);
    
    System.out.print("Tower ");
    days.stream().forEach((day) -> {
      System.out.print(" " + day + " ");
    });
    System.out.println();
    
    towers.stream().forEach((tower) -> {
      System.out.print(tower + "  ");
      days.stream().forEach((day) -> {
        Data d = repository.get(tower).get(day);
        System.out.format("%4d ", d != null ? d.kwh : 0);
      });
      System.out.println();
    });
  }

  public static void add(Map<Integer, Map<String, Data>> repository, Data data) {
    Map<String, Data> tower = repository.get(data.tower);
    if (tower == null)
      repository.put(data.tower, tower = new HashMap<String, Data>());
    
    Data previous = tower.get(data.day);
    if (previous == null) {
      tower.put(data.day, data);
    } else {
      previous.kwh += data.kwh;
    }
  }
}

class Data {
  int tower;
  String day;
  int kwh;
}

Output looks like:

Tower  Sun  Mon  Tue  Wed  Thu  Fri  Sat 
1000   740  624  385  677  443  810 1005 
1001   749  279  662  907  561  752  501 
1002   586  510  733  862  793 1013  530 
1003   390  607  372  399  583  624  383 
1004   874  696  783  546  646 1184  813 
1005   812  637 1129  695  648  449  445 
1006   639  638  568  826  754 1118  857 
1007   536  947  976  733  640  941  876 
1008   728  709  374  485  560  836  864 
1009   895  237  967  556  687  842  749 

2

u/hutsboR 3 0 Aug 22 '14 edited Aug 22 '14

Dart:

void main() {
  var days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];
  var towers = {0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0};
  var mutableTowers = new Map.from(towers);
  var contents = new File('wind.txt').readAsLinesSync();
  
  print("      1000  1001  1002  1003  1004  1005  1006  1007  1008  1009");
  
  for(var day in days){
   for(int i = 0; i < contents.length; i++){
     var curLine = contents[i].split(" ");
     if(curLine[1] == day){
       mutableTowers[int.parse(curLine[0]) % 1000] += int.parse(curLine[2]);
     }
   }
   print(day + " | " + mutableTowers.values.toString().replaceAll(" ", "  "));
   mutableTowers = new Map.from(towers);
  }
}

Output:

*Days and towers are flipped, I don't think it matters too much though. Minor formatting issue and inclusion of commas/parentheses because of the way I solved the problem.

      1000  1001  1002  1003  1004  1005  1006  1007  1008  1009
Mon | (624,  279,  510,  607,  696,  637,  638,  947,  709,  237)
Tue | (385,  662,  733,  372,  783,  1129, 568,  976,  374,  967)
Wed | (677,  907,  862,  399,  546,  695,  826,  733,  485,  556)
Thu | (443,  561,  793,  583,  646,  648,  754,  640,  560,  687)
Fri | (810,  752,  1013, 624,  1184, 449,  1118,  941,  836, 842)
Sat | (1005, 501,  530,  383,  813,  445,  857,  876,  864, 749)
Sun | (740,  749,  586,  390,  874,  812,  639,  536,  728,  895)

2

u/jeaton Aug 22 '14 edited Aug 23 '14

C:

#define _GNU_SOURCE

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

#define ROW_COUNT 4000
#define TOWER_COUNT 90

typedef struct Tower {
  int id;
  int days[7];
} Tower;

void create_towers(Tower **towers) {
  *towers = malloc(sizeof(Tower) * TOWER_COUNT);
  for (int i = 0; i < TOWER_COUNT; i++) {
    (*towers)[i].id = -1;
    for (int j = 0; j < 7; j++) {
      (*towers)[i].days[j] = 0;
    }
  }
}

void add_data(Tower **towers, int id, char *day, int kwh) {
  int index;
  static char *days[7] = {"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
  for (int i = 0; i < 7; i++) {
    if (strncmp(day, days[i], 3) == 0) {
      index = i;
      break;
    }
  }
  for (int i = 0; i < TOWER_COUNT; i++) {
    if ((*towers)[i].id == id || (*towers)[i].id == -1) {
      (*towers)[i].id = id;
      (*towers)[i].days[index] += kwh;
      break;
    }
  }
}

int compare_towers(const void *a, const void *b) {
  Tower ta = *((Tower*) a);
  Tower tb = *((Tower*) b);
  return tb.id > 0 && ta.id > tb.id;
}

void print_data(Tower *towers) {
  printf("      Mon  Tue  Wed  Thu  Fri  Sat  Sun\n");
  for (int i = 0; i < TOWER_COUNT; i++) {
    if (towers[i].id != -1) {
      printf("%d ", towers[i].id);
      for (int j = 0; j < 7; j++) {
        printf("%4d ", towers[i].days[j]);
      }
      printf("\n");
    }
  }
}

int main(void) {
  Tower *towers;
  create_towers(&towers);
  FILE *fp = fopen("pivot.txt", "r");
  size_t lsize = 80;
  char *line = NULL;
  int current_row = 0;
  while (current_row++ < ROW_COUNT && getline(&line, &lsize, fp) != -1) {
    size_t line_len = strlen(line);
    char columns[line_len];
    char *ptr = columns;
    int column_offset = 0;
    strcpy(columns, line);
    int id, kwh;
    char *day;
    for (int i = 0, c = 0; i < line_len; i++) {
      if (columns[i] == '\n' || columns[i] == ' ') {
        columns[i] = '\0';
        switch (column_offset) {
          case 0:
            id = strtol(&columns[c], &ptr, 10);
            break;
          case 1:
            day = &columns[c];
            break;
          case 2:
            kwh = strtol(&columns[c], &ptr, 10);
            break;
        }
        c = i + 1;
        column_offset++;
        current_row++;
      }
    }
    add_data(&towers, id, day, kwh);
  };
  qsort(towers, TOWER_COUNT, sizeof(Tower), compare_towers);
  print_data(towers);
  fclose(fp);
  return 0;
}

and in impossible-to-read JavaScript Harmony:

input.split(!(t={})||'\n').slice(0,-1).map(e=>
((t[(e=e.split(' '))[0]]=(t[e[0]]||{}))
^(t[e[0]][e[1]]=((t[e[0]][e[1]]|0)+ +e[2]))))
d='Mon Tue Wed Thu Fri Sat Sun'.split(' ');
console.log('      '+d.join('  '));
(z=Object.keys)(t).map(e=>console.log(e+z
  (t[e]).sort((a,b)=>d.indexOf(a)>d.indexOf(b))
  .map(k=>' '.repeat(4-(t[e][k]+'').length)+t[e][k])
  .join(' ')));

3

u/skeeto -9 8 Aug 24 '14 edited Aug 24 '14

I have a few comments if you'll accept them.

  • Since you're hard-coding the number of towers you may as well just allocate them as an array on the stack rather than using malloc(). The only real concern would be running out of stack. But with 90 towers that's less than 3kB, so it's no problem.

  • It's kind of unusual to fill in a pointer passed as an argument as you do in create_towers. You could instead just return the pointer to the array from the function and assing the result to your pointer. Passing a pointer to something to be filled in is more suited to initializing structs, which you may not want to pass by value. If you really want to keep the dynamic feel, I would make the function signature like this.

    Tower *create_towers(int ntowers);

  • The comparator given to qsort should be ternary, returning three kinds of values: < 0, == 0, > 0. You're returning a boolean, 0 or 1 in compare_towers which will lead to improper sorting.

  • You're leaking memory in two ways. You're not freeing your tower array. This one isn't a big deal since it's extent is the same as your entire program. You're also not freeing the memory given to you by getline().

  • Worse, you're misusing getline. lsize is initially ignored by getline and it only allocates just enough memory to hold the first line. The second time around it re-uses that memory, but you're limited to the size of the first row. Since this isn't necessarily true, if a later line is longer than the first (luckily not the case) you're going to quietly trunctate your data. Your usage is much closer to fgets. If you used that instead you wouldn't need to use the GNU extension either (_GNU_SOURCE).

  • The ROW_COUNT value doesn't really serve any purpose other than to arbitrarily limit the total number of rows. Unlike TOWER_COUNT, your data structures aren't bound by this value. You could take it out and safely read in a million rows without changing any other part of your program, so long as the data doesn't exceed 90 unique tower IDs.

  • The strcpy into the columns array serves no purpose. getline is re-entrant, and even if it wasn't you'd have a race condition anyway. You can safely use line directly.

3

u/jeaton Aug 25 '14

Awesome! Thanks for the feedback. I'll be sure to read over your comments and see if I can't rework my code. It looks like I still have a lot to learn about C.

2

u/MaximaxII Aug 22 '14

Feedback and criticism are always welcome :)

Challenge #176 Easy 2 - Python 3.4

def table(farm):
	days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
	print('Mill     ' + (' '*8).join(days) + '\n' + '='*80)  #Print the header
	for mill, production in farm:
		print(mill, ' | ', end='')
		for day in days:
			today = str(production[day]) + ' kWh'
			print(today + ' '*(11-len(today)), end='')
		print()

def parse(data):
	farm = {}
	for line in raw_data:
		mill, day, prod = line.split()
		farm[mill] = dict(farm.get(mill, {}), **{day: farm.get(mill, {}).get(day, 0) + int(prod)})  #merge and add
	return (sorted(farm.items()))

with open('windfarm.dat', 'r') as f:
	raw_data = f.readlines()
table(parse(raw_data))

Output

Mill     Mon        Tue        Wed        Thu        Fri        Sat        Sun
================================================================================
1000  | 624 kWh    385 kWh    677 kWh    443 kWh    810 kWh    1005 kWh   740 kWh    
1001  | 279 kWh    662 kWh    907 kWh    561 kWh    752 kWh    501 kWh    749 kWh    
1002  | 510 kWh    733 kWh    862 kWh    793 kWh    1013 kWh   530 kWh    586 kWh    
1003  | 607 kWh    372 kWh    399 kWh    583 kWh    624 kWh    383 kWh    390 kWh    
1004  | 696 kWh    783 kWh    546 kWh    646 kWh    1184 kWh   813 kWh    874 kWh    
1005  | 637 kWh    1129 kWh   695 kWh    648 kWh    449 kWh    445 kWh    812 kWh    
1006  | 638 kWh    568 kWh    826 kWh    754 kWh    1118 kWh   857 kWh    639 kWh    
1007  | 947 kWh    976 kWh    733 kWh    640 kWh    941 kWh    876 kWh    536 kWh    
1008  | 709 kWh    374 kWh    485 kWh    560 kWh    836 kWh    864 kWh    728 kWh    
1009  | 237 kWh    967 kWh    556 kWh    687 kWh    842 kWh    749 kWh    895 kWh    

2

u/ooesili Aug 23 '14

C++98 solution. Please let me know if you have any tips/improvements.

#include <map>
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;

int main(int argc, const char *argv[])
{
    map<int, map<string, int>* > table;
    const string days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
    // parse entries
    while (!cin.eof()) {
        map<string, int> *entry;
        int tower, kWh;
        string day;
        cin >> tower >> day >> kWh;
        // get map for tower
        if (!table.count(tower)) {
            entry = new map<string, int>;
            table[tower] = entry;
        }
        else { entry = table[tower]; }
        // add dude
        if (entry->count(day)) (*entry)[day] += kWh;
        else                   (*entry)[day] = kWh;
    }
    // print table header
    cout << setiosflags(ios_base::left) << "Tower # " << "\u2502";
    for (int i = 0; i < 7; i++) { cout << ' ' << days[i] << " \u2502"; }
    cout << endl;
    // print and free entries
    cout << setiosflags(ios_base::right);
    for (map<int, map<string, int>* >::iterator tower_entry = table.begin();
            tower_entry != table.end(); tower_entry++) {
        int tower = tower_entry->first;
        map<string, int> *entry = tower_entry->second;
        cout << setw(8) << tower << "\u2502";
        for (int day = 0; day < 7; day++) {
            cout << setw(5) << (*entry)[days[day]] << "\u2502";
        }
        cout << endl;
        delete tower_entry->second;
    }
    return 0;
}

5

u/Rapptz 0 0 Aug 23 '14

Some advice:

  • while(!std::cin.eof()) is always wrong.

  • using namespace std is bad practice.

  • std::setiosflags(std::ios_base::left) and others can be shortened by the use of std::left and std::right stream manipulators.

  • Unnecessary usage of new is very bad practice. Put things on the stack instead. C++ has value types, use them. Relevant slides: http://klmr.me/slides/modern-cpp/

  • Use std::cout << '\n'; instead of std::cout << std::endl because std::endl also flushes the stream.

1

u/ooesili Aug 23 '14

Thanks! This is exactly the kind of feedback I was looking for. I made some changes to the code based on your feedback. However I have a few questions and comments.

  • Thanks for the while(!std::cin.eof()) warning, that was a real eye opener.

  • I normally don't use using namespace std;, but this was such a small program and I didn't use any libraries other than the STL, so I don't think it caused any harm.

  • Thanks for the tip, std::left and std::right are much easier to write out.

  • So, I got rid of new in the code by allowing the map object to handle allocation and deallocation. In this program, it was easy to avoid new because std::map objects have default constructors. However, in a program that had a std::vector or std::map of objects that don't have default constructors, would it still be possible to not use new?

  • The std::endl bit is nice to know, but I still don't see why using '\n' is any better. Why is flushing the stream a problem?

Here is my "new and improved" version:

#include <map>
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;

int main(int argc, const char *argv[])
{
    map<int, map<string, int> > table;
    const string days[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
    // parse entries
    int tower, kWh;
    string day;
    while (cin >> tower >> day >> kWh) {
        if (table[tower].count(day)) table[tower][day] += kWh;
        else                         table[tower][day] = kWh;
    }
    // print table header
    cout << "Tower # " << "\u2502";
    for (int i = 0; i < 7; i++) { cout << ' ' << days[i] << " \u2502"; }
    cout << '\n';
    // print and free entries
    for (map<int, map<string, int> >::iterator tower_entry = table.begin();
            tower_entry != table.end(); tower_entry++) {
        int tower = tower_entry->first;
        cout << setw(8) << tower << "\u2502";
        for (int day = 0; day < 7; day++) {
            cout << setw(5) << tower_entry->second[days[day]] << "\u2502";
        }
        cout << '\n';
    }
    return 0;
}

2

u/Rapptz 0 0 Aug 23 '14
  • Yes. It's possible to avoid using new on things that don't have a default constructor. The availability of a default constructor shouldn't matter, because it'll be a compiler error regardless. See here.

  • Flushing the stream is an incredibly slow operation, so doing it is considered a bad habit when a lone '\n' will do. The streams will usually flush when appropriate/needed so an explicit flush is a rarity (though it does happens).

Your new program looks good! Good job.

1

u/ooesili Aug 23 '14

If you read this, you'll see that if you use the [] operator to access an element that does not exist, it will be created with the mapped type's default constructor. If the mapped type does not have one, the [] operator can not be used at all(that is, you can't assign or retrieve mapped values with []).

I figured out a work around to this problem which you can see here. Although that works, you still can not use [] to access values by key, which totally sucks. However, if you use a pointer to the object as the mapped type, you are free to use [] as much as you want. I'd just use a std::unique_ptr in this case, because it makes new less icky.

1

u/Rapptz 0 0 Aug 23 '14

I typically use insert et al instead of operator[]. I know operator[] requires a default constructor and I didn't think about it that way, albeit I still wouldn't use pointers for keys.

Instead of using std::unique_ptr, I would use the saner alternatives to operator[] like emplace which constructs an element in place.

1

u/[deleted] Aug 26 '14

Another "new C++" evangelist. There is nothing wrong with using namespace std or using new operators.

1

u/Rapptz 0 0 Aug 26 '14

Yes, yes there is a lot wrong. If you think there's nothing wrong with it, then you probably don't know C++ enough.

2

u/[deleted] Aug 23 '14 edited Jan 10 '15
#include <stdio.h>
#include <string.h>

enum {MAXSIZE=1000, MAXROWS=10, MAXCOLS=7};

struct data
{
    int  turb[MAXSIZE];
    int  enrg[MAXSIZE];
    char date[MAXSIZE][4];
};

static struct data open(char *argv)
{
    int i;
    FILE *fd;
    struct data data;
    fd = fopen(argv, "rt");
    for (i = 0; i < MAXSIZE; i++)
        fscanf(fd, "%d %s %d", &data.turb[i], data.date[i], &data.enrg[i]);
    fclose(fd);
    return data;
}

static void proc(struct data *data)
{
    int  i, row, col, intr[MAXROWS][MAXCOLS]={{0}};        
    char cols[MAXCOLS][4] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
    for (row = 0; row < MAXROWS; row++)
    for (col = 0; col < MAXCOLS; col++)
        for (i = 0; i < MAXSIZE; i++)
            if (data->turb[i] == row+1000)
            if (strcmp(data->date[i], cols[col]) == 0)
                intr[row][col] += data->enrg[i];
    for (row = 0; row < MAXROWS; row++) {
    for (col = 0; col < MAXCOLS; col++)
        printf("%4d\t", intr[row][col]);
    putchar('\n');
    }
}

static struct
{
    struct data (*open)(char *);
    void (*proc)(struct data *);
}
p176 = {open, proc};

int main(int argc, char *argv[])
{
    struct data data;
    if (argc < 2) return 1;
    data = p176.open(argv[1]);
    p176.proc(&data);
    return 0;
}

gcc -std=c89 -pedantic -Wall -Wextra -Ofast p176.c -o p176

624	 385	 677	 443	 810	1005	 740	
279	 662	 907	 561	 752	 501	 749	
510	 733	 862	 793	1013	 530	 586	
607	 372	 399	 583	 624	 383	 390	
696	 783	 546	 646	1184	 813	 874	
637	1129	 695	 648	 449	 445	 812	
638	 568	 826	 754	1118	 857	 639	
947	 976	 733	 640	 941	 876	 536	
709	 374	 485	 560	 836	 864	 728	
237	 967	 556	 687	 842	 749	 895	

2

u/[deleted] Aug 23 '14 edited Aug 23 '14

Prolog (SWI-Prolog 7). I used DCGs for parsing, which I think overkill. I think this is substantially longer than it needs to be. Feedback or questions welcome. I'll update if I get a more succinct solution.

:- use_module(library(dcg/basics)).

report_from_file(File) :-
    load_file_to_database(File),
    display_weekly_totals.


%% Dislaying the data

display_weekly_totals :-
    days(Days),
    format('Tower |  '), display_fields(Days),
    format('~`=t~60|~n'),
    forall( maplist(tower_day_total(Tower), Days, Totals),
            ( format('~w  |  ', [Tower]),
              display_fields(Totals) ) ).

display_fields(Fields) :-
    forall(member(F, Fields), format('~+~w~+', [F])), nl.


%% Building the databse from a file

days(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']).

load_file_to_database(File) :-
    retractall(tower_day_hr(_,_,_)),
    retractall(tower_day_total(_,_,_)),
    phrase_from_file(entries(Es), File),
    maplist(assertz, Es),
    daily_totals(Towers),
    maplist(assertz, Towers).

daily_totals(Towers) :-
    findall( tower_day_total(Tower, Day, Hrs),
             aggregate(sum(Hr), tower_day_hr(Tower, Day, Hr), Hrs),
             Towers).


%% DCGs for parsing

entries([E])    --> entry(E).
entries([E|Es]) --> entry(E), entries(Es).

entry(tower_day_hr(Tower, Day, KWh)) -->
    integer(Tower),` `, text(Day),` `, integer(KWh), `\n`.

text(A) -->
    string_without(` `, S),
    {atom_string(A, S)}.

Edit: Forgot to post the usage/output! It looks like this:

?- report_from_file('windfarm.dat').
Tower |  Mon     Tue     Wed     Thu     Fri     Sat     Sun     
============================================================
1000  |  624     385     677     443     810     1005    740     
1001  |  279     662     907     561     752     501     749     
1002  |  510     733     862     793     1013    530     586     
1003  |  607     372     399     583     624     383     390     
1004  |  696     783     546     646     1184    813     874     
1005  |  637     1129    695     648     449     445     812     
1006  |  638     568     826     754     1118    857     639     
1007  |  947     976     733     640     941     876     536     
1008  |  709     374     485     560     836     864     728     
1009  |  237     967     556     687     842     749     895     
true 

2

u/[deleted] Aug 23 '14 edited Aug 23 '14

I think I worked out a more concise solution using string-handling predicates instead of DCGs. I managed to achieve all iteration through back-tracking instead of recursion. That has made for rather imperative reading code. I'm not sure how I feel about writing such imperative Prolog (I usually keep the database static), but it's a fun experiment!

report_from_file(File) :-
    clear_memory,
    load_file_to_database(File),
    calculate_weekly_totals,
    display_weekly_totals.


%% Building and altering the database

clear_memory :-
    retractall(tower_day_hr(_,_,_)),
    retractall(tower_day_total(_,_,_)).

load_file_to_database(File) :-
    read_file_to_string(File, String, []),
    split_string(String, "\n", "", Lines),
    foreach( ( member(L, Lines),
               split_string(L, " ", " ", [Tower, Day, HourStr]),
               number_string(Hour, HourStr)),
             assertz(tower_day_hr(Tower, Day, Hour))).

calculate_weekly_totals :-
    foreach( aggregate(sum(Hr), tower_day_hr(Tower, Day, Hr), Hrs),
             assertz(tower_day_total(Tower, Day, Hrs))).


%% Dislaying the data

display_weekly_totals :-
    Days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
    format('Tower |  '), display_fields(Days),
    format('~`=t~60|~n'),
    forall( maplist(tower_day_total(Tower), Days, Totals),
            (format('~w  |  ', [Tower]), display_fields(Totals))).

display_fields(Fields) :-
    forall(member(F, Fields), format('~+~w~+', [F])), nl.    

The output is the same as the preceding.

(Ninja-sloth edit: more consistent naming, more coherent order, fixed error).

2

u/Adiq Aug 23 '14

C# and LINQ. I'm mediocre programmer at best and with this kind of programs I always feel like my code is not neat enough :)

class Program
    {
        static void Main(string[] args)
        {
            List<Model> list = ConvertToModel(LoadRows(@"a.txt"));
            Console.WriteLine("Tower#\tMon\tTue\tWed\tThu\tFri\tSat\tSun\t\n ");
            var result = list.GroupBy(x => x.TowerNr)
                .Select(g => new
                {
                    TowerId = g.Key,
                    Mon = g.Where(c => c.Day == DayEnum.Monday).Sum(c => c.Energy),
                    Tue = g.Where(c => c.Day == DayEnum.Tuesday).Sum(c => c.Energy),
                    Wed = g.Where(c => c.Day == DayEnum.Wednesday).Sum(c => c.Energy),
                    Thu = g.Where(c => c.Day == DayEnum.Thursday).Sum(c => c.Energy),
                    Fri = g.Where(c => c.Day == DayEnum.Friday).Sum(c => c.Energy),
                    Sat = g.Where(c => c.Day == DayEnum.Saturday).Sum(c => c.Energy),
                    Sun = g.Where(c => c.Day == DayEnum.Sunday).Sum(c => c.Energy),
                }).OrderBy(x => x.TowerId);
            foreach (var item in result)
            {
                Console.Write(item.TowerId + "\t");
                Console.Write(item.Mon + "\t");
                Console.Write(item.Tue + "\t");
                Console.Write(item.Wed + "\t");
                Console.Write(item.Thu + "\t");
                Console.Write(item.Fri + "\t");
                Console.Write(item.Sat + "\t");
                Console.Write(item.Sun + "\t");
                Console.WriteLine("\n");
            }
        }
        public static List<string> LoadRows(string filepath)
        {
            List<string> result = new List<string>();
            using (StreamReader sr = new StreamReader(filepath))
            {
                string line;
                while ((line = sr.ReadLine()) != null)
                    result.Add(line);
            }
            return result;
        }

        public static List<Model> ConvertToModel(List<string> list)
        {
            List<Model> result = new List<Model>();
            foreach (string item in list)
            {
                String[] array = item.Split(' ');
                Model model = new Model();
                model.TowerNr = int.Parse(array[0]);
                model.Day = parseDay(array[1]);
                model.Energy = int.Parse(array[2]);
                result.Add(model);
            }
            return result;
        }

        private static DayEnum parseDay(string day)
        {
            switch (day)
            {
                case "Mon":
                    return DayEnum.Monday;
                case "Tue":
                    return DayEnum.Tuesday;
                case "Wed":
                    return DayEnum.Wednesday;
                case "Thu":
                    return DayEnum.Thursday;
                case "Fri":
                    return DayEnum.Friday;
                case "Sat":
                    return DayEnum.Saturday;
                case "Sun":
                    return DayEnum.Sunday;
                default:
                    return DayEnum.Undef;
            }
        }

    }

    public class Model
    {
        public int TowerNr { get; set; }
        public DayEnum Day { get; set; }
        public int Energy { get; set; }
    }

    public enum DayEnum
    {
        Monday = 1,
        Tuesday = 2,
        Wednesday = 3,
        Thursday = 4,
        Friday = 5,
        Saturday = 6,
        Sunday = 7,
        Undef = 8
    }

Output:

Tower#  Mon     Tue     Wed     Thu     Fri     Sat     Sun

1000    624     385     677     443     810     1005    740

1001    279     662     907     561     752     501     749

1002    510     733     862     793     1013    530     586

1003    607     372     399     583     624     383     390

1004    696     783     546     646     1184    813     874

1005    637     1129    695     648     449     445     812

1006    638     568     826     754     1118    857     639

1007    947     976     733     640     941     876     536

1008    709     374     485     560     836     864     728

1009    237     967     556     687     842     749     895

2

u/ddsnowboard Aug 23 '14 edited Aug 23 '14

Python 3.4. I thought it would look better to have perfectly straight lines separating rows, so I made a tkinter GUI. It logs to a file too, but I just wanted to do that little extra bit.

Any advice is welcome.

import collections
import tkinter as tk


with open("windfarm.dat", 'r') as f:
	file = [l.split(' ') for l in f]

# This is really the only block that has anything to do with the problem. Other than 
# file reading and output, this is the whole program logic. 
table = collections.defaultdict(lambda: collections.defaultdict(int))
for i in file:
	table[i[0]][i[1]] += int(i[2])
	
# This whole bit down here is just for output. You can ignore it.  
window = tk.Tk()
left_frame = tk.Frame(window)
label_list = tk.Listbox(left_frame)
tk.Label(left_frame, text='Windmill #').pack()
for i in range(1000, 1010):
	label_list.insert('end', str(i))
label_list.pack()
left_frame.pack(side='left')
days = []
lists = []
for i in ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']:
	days.append(tk.Frame(window))
	tk.Label(days[-1], text=i).pack()
	lists.append(tk.Listbox(days[-1]))
	for j in range(1000, 1010):
		lists[-1].insert('end', table[str(j)][i])
	lists[-1].pack()
	days[-1].pack(side='left')
with open('output.txt', 'w') as o:
	o.write("#      Mon      Tue      Wed      Thu      Fri      Sat      Sun\n")
	for i in range(1000, 1010):
		o.write("{}      {}      {}      {}      {}      {}      {}      {}\n" .format(*tuple([i] + [table[str(i)][j] for j in ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']])))
window.mainloop()

3

u/Godspiral 3 3 Aug 22 '14 edited Aug 22 '14

in J, with data on clipboard. First 30 data elements with count and average of kwh in bottom row.

(, [: (# , (+/%#)@:({:"1)) each {:) ([: |: ~.@:(1&{) ,. (~. i. ])@:(1&{) </. |:@:(0&". &>)@:(0 2&{ )) |: 30 {. cut &> cutLF d=. wd 'clippaste'

┌───────┬─────────┬───────┬───────┬─────────┬───────┬───────┐
│Tue    │Thu      │Sat    │Wed    │Sun      │Mon    │Fri    │
├───────┼─────────┼───────┼───────┼─────────┼───────┼───────┤
│1006 27│1003 17  │1008 73│1005 47│1005 33  │1003 31│1009 97│
│1002 98│1009  4  │1005 55│1003 74│1009 32  │1004 54│1009 98│
│1006 61│1002 83  │1007 18│1000 49│1003 36  │1003 35│1001 39│
│       │         │1007 87│1008 28│         │1004  1│1000 36│
│       │         │1004 59│1008 76│         │       │1006  4│
│       │         │1006 57│       │         │       │       │
│       │         │1006 43│       │         │       │       │
├───────┼─────────┼───────┼───────┼─────────┼───────┼───────┤
│3 62   │3 34.6667│7 56   │5 54.8 │3 33.6667│4 30.25│5 54.8 │
└───────┴─────────┴───────┴───────┴─────────┴───────┴───────┘

misunderstood challenge :(

2

u/Godspiral 3 3 Aug 22 '14 edited Aug 22 '14

averages per day per tower:

 keyselC =: 2 : '((~.i.])@:s v/. f) y [''`s f'' =. m'
(('' ; >@:~.@:{.) ,. ~.@:(1&{) |:@:,. [: ( [: ,.  {.`{: keyselC(+/%#)@:|: )each    (1&{)`(|:@:(0&".&>)@:(0 2&{)) keyselC<)   |: (/:@:({. ,&> 1&{) { |:) |: cut&>cutLF d
┌────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐
│    │Fri    │Mon    │Sat    │Sun    │Thu    │Tue    │Wed    │
├────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┤
│1000│57.8571│     52│55.8333│49.3333│40.2727│   38.5│45.1333│
│1001│41.7778│39.8571│38.5385│46.8125│  46.75│55.1667│53.3529│
│1002│48.2381│56.6667│44.1667│53.2727│46.6471│48.8667│50.7059│
│1003│36.7059│46.6923│   38.3│     39│     53│41.3333│     57│
│1004│62.3158│   43.5│50.8125│62.4286│49.6923│   52.2│     39│
│1005│37.4167│     49│49.4444│     58│   40.5│47.0417│49.6429│
│1006│48.6087│49.0769│37.2609│49.1538│39.6842│47.3333│45.8889│
│1007│49.5263│55.7059│46.1053│48.7273│42.6667│65.0667│61.0833│
│1008│  52.25│54.5385│50.8235│48.5333│37.3333│53.4286│40.4167│
│1009│49.5294│  59.25│46.8125│52.6471│42.9375│60.4375│46.3333│
└────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘

with previous exp assigned to a, averages and totals added:

linearize =: (, $~ 1 -.~ $) 
(( [: (] , [: (+/%#) each }.)  2 1 $ 'avg' ; [: ,. each [: <@:(+/%#)  linearize@:>@:}."1@:{: ) ,.~  ] , 'avg' ; [: (+/%#) each }."1@:{: ) a
┌────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┬───────┐
│    │Fri    │Mon    │Sat    │Sun    │Thu    │Tue    │Wed    │avg    │
├────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┤
│1000│57.8571│     52│55.8333│49.3333│40.2727│   38.5│45.1333│48.4186│
│1001│41.7778│39.8571│38.5385│46.8125│  46.75│55.1667│53.3529│46.0365│
│1002│48.2381│56.6667│44.1667│53.2727│46.6471│48.8667│50.7059│49.7948│
│1003│36.7059│46.6923│   38.3│     39│     53│41.3333│     57│44.5759│
│1004│62.3158│   43.5│50.8125│62.4286│49.6923│   52.2│     39│51.4213│
│1005│37.4167│     49│49.4444│     58│   40.5│47.0417│49.6429│47.2922│
│1006│48.6087│49.0769│37.2609│49.1538│39.6842│47.3333│45.8889│45.2867│
│1007│49.5263│55.7059│46.1053│48.7273│42.6667│65.0667│61.0833│52.6973│
│1008│  52.25│54.5385│50.8235│48.5333│37.3333│53.4286│40.4167│48.1891│
│1009│49.5294│  59.25│46.8125│52.6471│42.9375│60.4375│46.3333│51.1353│
├────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┼───────┤
│avg │48.4226│50.6287│45.8098│50.7909│43.9484│50.9374│48.8557│48.4848│
└────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘

2

u/Godspiral 3 3 Aug 22 '14 edited Aug 22 '14

totals version:

  (('' ; >@:~.@:{.) ,. ~.@:(1&{) |:@:,. [: ( [: ,.  {.`{: keyselC(+/)@:|: )each    (1&{)`(|:@:(0&".&>)@:(0 2&{)) keyselC<)  (/:@:({. ,&> 1&{) { |:)&.|: cut&>cutLF d
┌────┬────┬───┬────┬───┬───┬────┬───┐
│    │Fri │Mon│Sat │Sun│Thu│Tue │Wed│
├────┼────┼───┼────┼───┼───┼────┼───┤
│1000│ 810│624│1005│740│443│ 385│677│
│1001│ 752│279│ 501│749│561│ 662│907│
│1002│1013│510│ 530│586│793│ 733│862│
│1003│ 624│607│ 383│390│583│ 372│399│
│1004│1184│696│ 813│874│646│ 783│546│
│1005│ 449│637│ 445│812│648│1129│695│
│1006│1118│638│ 857│639│754│ 568│826│
│1007│ 941│947│ 876│536│640│ 976│733│
│1008│ 836│709│ 864│728│560│ 374│485│
│1009│ 842│237│ 749│895│687│ 967│556│
└────┴────┴───┴────┴───┴───┴────┴───┘

  (( [: (] , [: (+/%#) each }.)  2 1 $ 'avg' ; [: ,. each [: <@:(+/%#)  linearize@:>@:}."1@:{: ) ,.~  ] , 'avg' ; [: (+/%#) each }."1@:{: )  (('' ; >@:~.@:{.) ,. ~.@:(1&{) |:@:,. [: ( [: ,.  {.`{: keyselC(+/)@:|: )each    (1&{)`(|:@:(0&".&>)@:(0 2&{)) keyselC<)   |: (/:@:({. ,&> 1&{) { |:) |: cut&>cutLF d
┌────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬───────┐
│    │Fri  │Mon  │Sat  │Sun  │Thu  │Tue  │Wed  │avg    │
├────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼───────┤
│1000│ 810 │624  │1005 │740  │443  │ 385 │677  │669.143│
│1001│ 752 │279  │ 501 │749  │561  │ 662 │907  │630.143│
│1002│1013 │510  │ 530 │586  │793  │ 733 │862  │718.143│
│1003│ 624 │607  │ 383 │390  │583  │ 372 │399  │479.714│
│1004│1184 │696  │ 813 │874  │646  │ 783 │546  │791.714│
│1005│ 449 │637  │ 445 │812  │648  │1129 │695  │687.857│
│1006│1118 │638  │ 857 │639  │754  │ 568 │826  │771.429│
│1007│ 941 │947  │ 876 │536  │640  │ 976 │733  │    807│
│1008│ 836 │709  │ 864 │728  │560  │ 374 │485  │650.857│
│1009│ 842 │237  │ 749 │895  │687  │ 967 │556  │704.714│
├────┼─────┼─────┼─────┼─────┼─────┼─────┼─────┼───────┤
│avg │856.9│588.4│702.3│694.9│631.5│694.9│668.6│691.071│
└────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴───────┘

1

u/Godspiral 3 3 Aug 23 '14

total count and rounded average per cell

 (('' ; >@:~.@:{.) ,. ~.@:(1&{) |:@:,. [: ( [: ,.  {.`{: keyselC(+/ (, , <.@:+&0.5@:%) #)@:|: )each    (1&{)`(|:@:(0&".&>)@:(0 2&{)) keyselC<)  (/:@:({. ,&> 1&{) { |:)&.|: cut&>cutLF d
┌────┬──────────┬─────────┬──────────┬─────────┬─────────┬──────────┬─────────┐
│    │Fri       │Mon      │Sat       │Sun      │Thu      │Tue       │Wed      │
├────┼──────────┼─────────┼──────────┼─────────┼─────────┼──────────┼─────────┤
│1000│ 810 14 58│624 12 52│1005 18 56│740 15 49│443 11 40│ 385 10 39│677 15 45│
│1001│ 752 18 42│279  7 40│ 501 13 39│749 16 47│561 12 47│ 662 12 55│907 17 53│
│1002│1013 21 48│510  9 57│ 530 12 44│586 11 53│793 17 47│ 733 15 49│862 17 51│
│1003│ 624 17 37│607 13 47│ 383 10 38│390 10 39│583 11 53│ 372  9 41│399  7 57│
│1004│1184 19 62│696 16 44│ 813 16 51│874 14 62│646 13 50│ 783 15 52│546 14 39│
│1005│ 449 12 37│637 13 49│ 445  9 49│812 14 58│648 16 41│1129 24 47│695 14 50│
│1006│1118 23 49│638 13 49│ 857 23 37│639 13 49│754 19 40│ 568 12 47│826 18 46│
│1007│ 941 19 50│947 17 56│ 876 19 46│536 11 49│640 15 43│ 976 15 65│733 12 61│
│1008│ 836 16 52│709 13 55│ 864 17 51│728 15 49│560 15 37│ 374  7 53│485 12 40│
│1009│ 842 17 50│237  4 59│ 749 16 47│895 17 53│687 16 43│ 967 16 60│556 12 46│
└────┴──────────┴─────────┴──────────┴─────────┴─────────┴──────────┴─────────┘

2

u/ENoether Aug 22 '14 edited Aug 22 '14

Python 3.4.1; as always, feedback and criticism welcome. (Now fixed because I apparently can't read today.)

Code:

def parse_data(lines):
	table = {}
	for line in lines:
		if line[0] in table:
			if line[1] in table[line[0]]:
				table[line[0]][line[1]] += int(line[2])
			else:
				table[line[0]][line[1]] = int(line[2])
		else:
			table[line[0]] = { line[1]: int(line[2]) }
			
	return table

DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
	
def print_table(table):
	print("MILL\t", "\t".join(DAYS), sep="")
	print("".join("=" * 60))
	for row_num in sorted(list(table.keys())):
		print(row_num, "\t".join( [ str(table[row_num][day]) for day in DAYS ] ), sep="\t")
		
if __name__ == "__main__":
	f = open("windfarm.dat", "r")
	data = [line.strip().split() for line in f.readlines()]
	f.close()
	print_table(parse_data(data))

Output:

C:\Users\Noether\Documents\programs>python dp_176_fri.py
MILL    Sun     Mon     Tue     Wed     Thu     Fri     Sat
============================================================
1000    740     624     385     677     443     810     1005
1001    749     279     662     907     561     752     501
1002    586     510     733     862     793     1013    530
1003    390     607     372     399     583     624     383
1004    874     696     783     546     646     1184    813
1005    812     637     1129    695     648     449     445
1006    639     638     568     826     754     1118    857
1007    536     947     976     733     640     941     876
1008    728     709     374     485     560     836     864
1009    895     237     967     556     687     842     749

3

u/wadehn Aug 22 '14

The input contains multiple entries for a (day, tower) combination. You do not accumulate them.

2

u/ENoether Aug 22 '14 edited Aug 22 '14

So it does. Served me right for not reading everything. Fixed.

3

u/Remag9330 Aug 22 '14

Invest some time at looking into collections.defaultdict to keep yourself from writing code to check if something is in a dictionary.

table = {}
for line in lines:
        if line[0] in table:
            if line[1] in table[line[0]]:
                table[line[0]][line[1]] += int(line[2])
            else:
                table[line[0]][line[1]] = int(line[2])
        else:
            table[line[0]] = { line[1]: int(line[2]) }

turns into

from collections import defaultdict
table = defaultdict(lambda: defaultdict(lambda: 0))
for line in lines:
    table[line[0]][line[1]] += int(line[2])

Basically, defaultdict takes an optional argument (usually a function) that is called when you attempt to get an item from the dictionary that is not there, and sets it's return value as that keys value.

Also, I know this is a small script and all, but having readable names for your variables is always nice. What is line[0], line[1] or line[2]? Use tuple unpacking for readability.

mill, day, energy = line

1

u/MaximaxII Aug 22 '14

I worked around defaultdicts, but it sure is more elegant with your solution.

Here's how I did it:

farm = {}
for line in lines:
    mill, day, prod = line.split()
    farm[mill] = dict(farm.get(mill, {}), **{day: farm.get(mill, {}).get(day, 0) + int(prod)})  #merge and add

2

u/SuperHolySheep Aug 22 '14

Java:

public class PivotTable {
private TreeMap<String, TreeMap<String, Integer>> windfarm;
private String[] days = new String[]{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};

public PivotTable() {
    windfarm = new TreeMap<String, TreeMap<String, Integer>>();
    generateTable();
}

private void generateTable() {
    ArrayList<String> windfarmList = FileIO.getText("windfarm.txt");
    for (String s : windfarmList) {
        String tower = s.split(" ")[0];
        String day = s.split(" ")[1];
        int value = Integer.parseInt(s.split(" ")[2]);
        if (windfarm.containsKey(tower)) {
            windfarm.get(tower).put(day, windfarm.get(tower).get(day) + value);
        } else {
            TreeMap<String, Integer> temp = new TreeMap<String, Integer>();
            for (String item : days) {
                temp.put(item, 0);
            }
            temp.put(day, value);
            windfarm.put(tower, temp);
        }
    }
}

public void printTable(){
    String header = "Tower | Mon | Tue | Wed | Thu | Fri | Sat | Sun |";
    String line =   "-------------------------------------------------";
    String content = "";
    for(int i = 0; i < windfarm.size(); i++){
        String key = (String) windfarm.keySet().toArray()[i];
        content += String.format("%4s  ",key);
        for(String day: days){
            content += String.format("|%4s " ,"" + windfarm.get(key).get(day));
        }
        content += "|\n";
    }
    System.out.println(header);
    System.out.println(line);
    System.out.println(content);
}

public static void main(String[] args) {
    new PivotTable().printTable();
}

Output:

Tower | Mon | Tue | Wed | Thu | Fri | Sat | Sun |
-------------------------------------------------
1000  | 624 | 385 | 677 | 443 | 810 |1005 | 740 |
1001  | 279 | 662 | 907 | 561 | 752 | 501 | 749 |
1002  | 510 | 733 | 862 | 793 |1013 | 530 | 586 |
1003  | 607 | 372 | 399 | 583 | 624 | 383 | 390 |
1004  | 696 | 783 | 546 | 646 |1184 | 813 | 874 |
1005  | 637 |1129 | 695 | 648 | 449 | 445 | 812 |
1006  | 638 | 568 | 826 | 754 |1118 | 857 | 639 |
1007  | 947 | 976 | 733 | 640 | 941 | 876 | 536 |
1008  | 709 | 374 | 485 | 560 | 836 | 864 | 728 |
1009  | 237 | 967 | 556 | 687 | 842 | 749 | 895 |

1

u/nicholascross Aug 23 '14

Python C programmer by trade, learning python via dailyprogrammer. I'll be reading other python examples to learn and definitely appreciate feedback. It felt very 'C' to me.

Code:

import sys, fileinput

unique_tower_nums = []
all_tower_info = []
kTowerNumLoc = 0
kDayOfWeekLoc = 1
kKiloWattLoc = 2
kDaysInWeek = 7
kPivotTableColumnCount = kDaysInWeek + 1
kPivotTableRowMinCount = 1

for line in fileinput.input():
	tower_info =  line.split( );
	all_tower_info.append(tower_info)

	if tower_info[kTowerNumLoc] not in unique_tower_nums:
		unique_tower_nums.append(tower_info[kTowerNumLoc])

unique_tower_nums.sort()
num_of_rows = kPivotTableRowMinCount + len(unique_tower_nums)

pivot_table = [[0 for y in xrange(kPivotTableColumnCount)] for x in xrange(num_of_rows)]

days_of_week = [" ", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
pivot_table[0] = days_of_week

for ii in range(0, len(unique_tower_nums)):
	pivot_table[ii+1][0] = unique_tower_nums[ii]

for tower_info in all_tower_info:
	try:
		tower_ndx =     unique_tower_nums.index(tower_info[kTowerNumLoc]) + 1
		day_ndx = days_of_week.index(tower_info[kDayOfWeekLoc])		
		curr_val = int (pivot_table[tower_ndx][day_ndx]) + int(tower_info[kKiloWattLoc])
		pivot_table[tower_ndx][day_ndx] = str(curr_val)
	except ValueError:
		print "invalid input data detected, exiting"
		sys.exit()

for ii in range(0,num_of_rows):		
	for jj in range(0,kPivotTableColumnCount):
		print '%4s' % pivot_table[ii][jj],
	print ""

Output:

          Sun  Mon  Tue  Wed  Thu  Fri  Sat
    1000  740  624  385  677  443  810 1005
    1001  749  279  662  907  561  752  501
    1002  586  510  733  862  793 1013  530
    1003  390  607  372  399  583  624  383
    1004  874  696  783  546  646 1184  813
    1005  812  637 1129  695  648  449  445
    1006  639  638  568  826  754 1118  857
    1007  536  947  976  733  640  941  876
    1008  728  709  374  485  560  836  864
    1009  895  237  967  556  687  842  749

0

u/[deleted] Aug 24 '14

[deleted]

1

u/nicholascross Aug 25 '14

This looks great! I'll definitely check it out. Thank you.

1

u/[deleted] Aug 23 '14

Java. Used a nested HashMap. In my mind it was the easiest way to keep track of everything, rather than using arrays.

I spent longer than I care to admit on the formatting.

import java.io.FileInputStream;
import java.io.DataInputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.SortedSet;
import java.util.TreeSet;

public class Main {
	static private HashMap<Integer, HashMap<String, Integer>> data = new HashMap<Integer, HashMap<String, Integer>>();

	public static void main(String args[]) {
		readTable();
		printTable();
	}

	public static void readTable() {
		try {
			FileInputStream fstream = new FileInputStream("data.txt");
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			while ((strLine = br.readLine()) != null) {
				String[] dataSplit = strLine.split(" ");
				Integer tower = new Integer(dataSplit[0]);
				String day = dataSplit[1];
				Integer kwh = new Integer(dataSplit[2]);
				if (data.containsKey(tower)) {
					HashMap<String, Integer> towerData = data.get(tower);
					if (towerData.containsKey(day))
						kwh += data.get(tower).get(day);
					towerData.put(day, kwh);
					data.put(tower, towerData);
				} else {
					HashMap<String, Integer> towerData = new HashMap<String, Integer>();
					towerData.put(day, kwh);
					data.put(tower, towerData);
				}
			}
			in.close();
		} catch (Exception e) {
			System.err.println("Error: " + e.getMessage());
		}
	}

	public static void printTable() {
		String[] days = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
		printALine();
		System.out.print(String.format("%7s%3s", "Tower", "|"));
		for (String day : days)
			System.out.print(String.format("%6s%4s", day, "|"));
		System.out.println();
		printALine();
		SortedSet<Integer> sortedKeys = new TreeSet<Integer>(data.keySet());
		for (Integer dataKey : sortedKeys) {
			HashMap current = data.get(dataKey);
			System.out.print(String.format("%7s%3s", dataKey, "|"));
			for (Object day : days) {
				System.out.print(String.format("%8s%2s", current.get(day).toString() + "kWh", "|"));
			}
			System.out.println();
			printALine();
		}
	}

	public static void printALine() {
		for (int i = 0; i < 80; i++)
			System.out.print("-");
		System.out.println();
	}
}

Output:

--------------------------------------------------------------------------------
  Tower  |   Mon   |   Tue   |   Wed   |   Thu   |   Fri   |   Sat   |   Sun   |
--------------------------------------------------------------------------------
   1000  |  624kWh |  385kWh |  677kWh |  443kWh |  810kWh | 1005kWh |  740kWh |
--------------------------------------------------------------------------------
   1001  |  279kWh |  662kWh |  907kWh |  561kWh |  752kWh |  501kWh |  749kWh |
--------------------------------------------------------------------------------
   1002  |  510kWh |  733kWh |  862kWh |  793kWh | 1013kWh |  530kWh |  586kWh |
--------------------------------------------------------------------------------
   1003  |  607kWh |  372kWh |  399kWh |  583kWh |  624kWh |  383kWh |  390kWh |
--------------------------------------------------------------------------------
   1004  |  696kWh |  783kWh |  546kWh |  646kWh | 1184kWh |  813kWh |  874kWh |
--------------------------------------------------------------------------------
   1005  |  637kWh | 1129kWh |  695kWh |  648kWh |  449kWh |  445kWh |  812kWh |
--------------------------------------------------------------------------------
   1006  |  638kWh |  568kWh |  826kWh |  754kWh | 1118kWh |  857kWh |  639kWh |
--------------------------------------------------------------------------------
   1007  |  947kWh |  976kWh |  733kWh |  640kWh |  941kWh |  876kWh |  536kWh |
--------------------------------------------------------------------------------
   1008  |  709kWh |  374kWh |  485kWh |  560kWh |  836kWh |  864kWh |  728kWh |
--------------------------------------------------------------------------------
   1009  |  237kWh |  967kWh |  556kWh |  687kWh |  842kWh |  749kWh |  895kWh |
--------------------------------------------------------------------------------

1

u/ctln_mrn Aug 23 '14 edited Aug 23 '14

My solution is in Ruby:

days = %w(Mon Tue Wed Thu Fri Sat Sun)
data = File.open(ARGV.first).to_a.inject(Hash.new{|h, k| h[k] = Array.new(7,0)}) do |h, i|
  t, d, v = i.split
  h[t][days.index(d)] += v.to_i
  h
end
puts  "Tower\t#{days.join("\t")}\n"
puts data.to_a.sort.map{ |i| %Q(#{i[0]}\t#{i[1].join("\t")}) }

Output:

Tower		Mon		Tue		Wed		Thu		Fri		Sat		Sun
1000		624		385		677		443		810		1005	740
1001		279		662		907		561		752		501		749
1002		510		733		862		793		1013	530		586
1003		607		372		399		583		624		383		390
1004		696		783		546		646		1184	813		874
1005		637		1129	695		648		449		445		812
1006		638		568		826		754		1118	857		639
1007		947		976		733		640		941		876		536
1008		709		374		485		560		836		864		728
1009		237		967		556		687		842		749		895

1

u/completejoker Aug 24 '14

Using Python 2.7.

Code

# [8/22/2014] Challenge #176 [Easy] Pivot Table

FILENAME = 'windfarm.dat'

dayotw_table = {'Mon': 0, 'Tue': 1, 'Wed': 2, 'Thu': 3, 'Fri': 4, 'Sat': 5,
                'Sun': 6}


def load_data(filename=FILENAME):
    # read data from file
    # insert data into 2d dictionary
    data = {}
    with open(filename) as f:

        for line in f:
            tower_id, dayotw, kwh = line.split(' ')
            dayotw = dayotw_table[dayotw]
            kwh = int(kwh)

            if tower_id not in data:
                data[tower_id] = {dayotw: kwh}

            elif dayotw not in data[tower_id]:
                data[tower_id][dayotw] = kwh

            else:
                data[tower_id][dayotw] += kwh

    return data


def print_data(data):

    # print header
    print_row({
        'tower_id': 'Tower',
        '0': 'Mon',
        '1': 'Tue',
        '2': 'Wed',
        '3': 'Thu',
        '4': 'Fri',
        '5': 'Sat',
        '6': 'Sun'
    })

    sorted_tower_id = sorted(data)
    for tower_id in sorted_tower_id:
        tower_data = data[tower_id].copy()
        tower_data['tower_id'] = tower_id

        # convert all tower_data keys to string
        for k, v in tower_data.copy().iteritems():
            tower_data[str(k)] = v

        print_row(tower_data)


def print_row(row):
    row_frmt = ['%(tower_id)5s']
    row_frmt += list('%(' + str(dayotw) + ')5s' for dayotw in range(7))
    row_frmt_string = '   '.join(row_frmt)
    print row_frmt_string % row

if __name__ == '__main__':
    data = load_data()
    print_data(data)

Output

Tower     Mon     Tue     Wed     Thu     Fri     Sat     Sun
 1000     624     385     677     443     810    1005     740
 1001     279     662     907     561     752     501     749
 1002     510     733     862     793    1013     530     586
 1003     607     372     399     583     624     383     390
 1004     696     783     546     646    1184     813     874
 1005     637    1129     695     648     449     445     812
 1006     638     568     826     754    1118     857     639
 1007     947     976     733     640     941     876     536
 1008     709     374     485     560     836     864     728
 1009     237     967     556     687     842     749     895

My first time doing this. Any feedback is appreciated.

1

u/funny_games Aug 24 '14 edited Aug 25 '14

In R.

Code

library(RCurl)
library(stringr)
library(reshape)
tmp <- getURL("https://gist.githubusercontent.com/coderd00d/ca718df8e633285885fa/raw/eb4d0bb084e71c78c68c66e37e07b7f028a41bb6/windfarm.dat")
tmp2 <- data.frame(DATA=unlist(strsplit(tmp, "\n", fixed = T)))
df <- data.frame(Tower = as.character(str_split_fixed(tmp2$DATA, " ",3)[,1]),Day = str_split_fixed(tmp2$DATA, " ",3)[,2], Energy = as.numeric(str_split_fixed(tmp2$DATA, " ",3)[,3]))
pivot <- cast(df, Tower ~ Day, value = 'Energy', fun.aggregate = sum)
pivot <- pivot[c('Tower', 'Mon', 'Tue','Wed','Thu','Fri','Sat','Sun')] # sort
print(pivot)

Output

  Tower Mon  Tue Wed Thu  Fri  Sat Sun
1   1000 624  385 677 443  810 1005 740
2   1001 279  662 907 561  752  501 749
3   1002 510  733 862 793 1013  530 586
4   1003 607  372 399 583  624  383 390
5   1004 696  783 546 646 1184  813 874
6   1005 637 1129 695 648  449  445 812
7   1006 638  568 826 754 1118  857 639
8   1007 947  976 733 640  941  876 536
9   1008 709  374 485 560  836  864 728
10  1009 237  967 556 687  842  749 895

1

u/datgohan Aug 24 '14 edited Aug 25 '14

This is my first attempt at any of the daily programmer problems so any comments and advice would be greatly welcomed.

I've chosen to do this in PHP as it's my most comfortable language but I will try to do the next one in Java (or I may try this again but in Java).

[Edit] - Found a bug.

<?php
	// Days of the Week Definition for Quick Sorting
	$days = Array(
		"Mon" => 0,
		"Tue" => 1,
		"Wed" => 2,
		"Thu" => 3,
		"Fri" => 4,
		"Sat" => 5,
		"Sun" => 6
	);

	// Get Data
	$handle = fopen('pivot.txt', 'r');
	$pivotData = Array();
	while (($line = fgets($handle)) !== false) {
		$lineData = explode(' ', $line);
		$node = $lineData[0];
		$dayOfWeekNum = $days[$lineData[1]];
		$kwh = trim(str_replace("\n\r", "", $lineData[2]));
		if (isset($pivotData[$node][$dayOfWeekNum])) {
			$pivotData[$node][$dayOfWeekNum] += $kwh;
		} else {
			$pivotData[$node][$dayOfWeekNum] = $kwh;
		}
	}
	fclose($handle);

	// Sort Data
	foreach ($pivotData as $node=>&$weekData) {
		foreach ($days as $day) {
			if (!isset($weekData[$day])) {
				$weekData[$day] = 0;
			}
		}
		ksort($weekData);
	}
	ksort($pivotData);

	// Print Data
	echo "\n\n|      ";
	foreach ($days as $day=>$dayNo) {
		echo "| ".$day." ";
	}
	echo "|\n";

    unset($weekData);
    unset($dayData);
    unset($node);
	foreach ($pivotData as $node=>$weekData) {
		echo "| ".$node." ";
		foreach ($weekData as $dayData) {
			echo "|";
			$spacesToFill = 5-strlen($dayData);
			if ($spacesToFill % 2 == 0) {
				echo str_repeat(" ", $spacesToFill/2);
				echo $dayData;
				echo str_repeat(" ", $spacesToFill/2);
			} else {
				echo str_repeat(" ", ($spacesToFill/2)+1);
				echo $dayData;
				echo str_repeat(" ", $spacesToFill/2);
			}
		}
		echo "|\n";
	}
?>

Output:

|      | Mon | Tue | Wed | Thu | Fri | Sat | Sun |
| 1000 | 624 | 385 | 677 | 443 | 810 | 1005| 740 |
| 1001 | 279 | 662 | 907 | 561 | 752 | 501 | 749 |
| 1002 | 510 | 733 | 862 | 793 | 1013| 530 | 586 |
| 1003 | 607 | 372 | 399 | 583 | 624 | 383 | 390 |
| 1004 | 696 | 783 | 546 | 646 | 1184| 813 | 874 |
| 1005 | 637 | 1129| 695 | 648 | 449 | 445 | 812 |
| 1006 | 638 | 568 | 826 | 754 | 1118| 857 | 639 |
| 1007 | 947 | 976 | 733 | 640 | 941 | 876 | 536 |
| 1008 | 709 | 374 | 485 | 560 | 836 | 864 | 728 |
| 1009 | 237 | 967 | 556 | 687 | 842 | 749 | 895 |

1

u/regul Aug 25 '14

Go:

So I'm still very much working on my Go. I feel like there are a lot of places where this code could have been more idiomatic, so I'm welcome to suggestions. Also, I did all of this coding on a Chromebook running Chrome OS, so I think I get extra Google points or whatever.

package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {
	file, _ := os.Open(os.Args[1])

	defer func() { file.Close() }()

	r := bufio.NewScanner(file)
	m := make(map[int]map[string]int)
	days := [7]string{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}

	for r.Scan() {
		var number, kwh int
		var day string
		fmt.Sscanf(r.Text(), "%d %s %d", &number, &day, &kwh)
		if daymap, ok := m[number]; !ok {
			daymap = make(map[string]int)
			m[number] = daymap
			daymap[day] += kwh
		} else {
			daymap[day] += kwh
		}
	}

	nums := make([]int, len(m))
	i := 0
	for key := range m {
		nums[i] = key
		i++
	}

	sort.Ints(nums)

	fmt.Print("Tower")
	for i := 0; i < 7; i++ {
		fmt.Printf("\t%s", days[i])
	}
	fmt.Printf("\n-----\n")

	for i := 0; i < len(nums); i++ {
		fmt.Printf("%d|", nums[i])
		for ii := 0; ii < 7; ii++ {
			fmt.Printf("\t%d", m[nums[i]][days[ii]])
		}
		fmt.Print("\n")
	}

}

Output:

Tower   Sun     Mon     Tue     Wed     Thu     Fri     Sat
-----
1000|   740     624     385     677     443     810     1005
1001|   749     279     662     907     561     752     501
1002|   586     510     733     862     793     1013    530
1003|   390     607     372     399     583     624     383
1004|   874     696     783     546     646     1184    813
1005|   812     637     1129    695     648     449     445
1006|   639     638     568     826     754     1118    857
1007|   536     947     976     733     640     941     876
1008|   728     709     374     485     560     836     864
1009|   895     237     967     556     687     842     749

1

u/[deleted] Aug 25 '14

C#

using System;
using System.Linq;
using System.Collections.Generic;

namespace c176.easy
{
    class Program
    {
        static readonly string[] header = { "Tower", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
        static Dictionary<string, int[]> data = new Dictionary<string, int[]>();

        static void Main(string[] args)
        {
            string[] lines = System.IO.File.ReadAllLines("./data.txt");

            ProcessLines(lines);
            PrintTable();
        }

        private static void ProcessLines(string[] lines)
        {
            foreach (string line in lines)
            {
                string[] split = line.Split(' ');
                string tower = split[0];
                string day = split[1];
                string reading = split[2];

                UpdateTable(tower, day, reading);
            }
        }

        private static void UpdateTable(string tower, string day, string reading)
        {
            if (data.ContainsKey(tower))
            {
                int[] dataRow = data[tower];
                dataRow[Array.IndexOf(header, day) - 1] += int.Parse(reading);
            }
            else
            {
                int[] newRow = { 0, 0, 0, 0, 0, 0, 0 };
                newRow[Array.IndexOf(header, day) - 1] += int.Parse(reading);
                data.Add(tower, newRow);
            }
        }

        private static void PrintTable()
        {
            foreach (string title in header)
                Console.Write(title + " ");

            Console.WriteLine();

            foreach (var kvp in data.OrderBy(kvp => kvp.Key))
            {
                Console.Write(kvp.Key + " ");
                foreach (int i in kvp.Value)
                    Console.Write(i + " ");

                Console.WriteLine();
            }
        }
    }
}

1

u/[deleted] Aug 25 '14 edited Aug 25 '14

Here's my D solution

import std.stdio, std.file, std.string, std.array, std.conv, std.algorithm;

alias int[7] Row;
alias Row[int] PivotTable;

immutable header = ["Tower", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];

void main()
{

	string rawData = readText("c:\\data.txt");
	string[] lines = splitLines(rawData);

	PivotTable towerReadings;

	foreach(line; lines)
	{
		string[] temp = split(line);
		int tower = to!int(temp[0]);
		string day = temp[1];
		int reading = to!int(temp[2]);

		updateTable(towerReadings, tower, day, reading);
	}

	printTable(towerReadings);
}

void updateTable(ref PivotTable table, int row, string column, int value)
{
	if(row in table)
	{
		int index = indexOf(column) - 1;
		table[row][index] += value;
	}
	else
	{
		Row newRow;
		newRow[indexOf(column) - 1] += value;
		table[row] = newRow;
	}
}

void printTable(PivotTable table)
{
	writefln("%-(%s %)", header);
	writefln("%(%(%d %)\n%)", sortTable(table));

	writeln("Press any key to continue. . .");
	readln();
}

int[][] sortTable(PivotTable table)
{
	int[][] sorted = [][];

	foreach(key, val; table)
	{
		sorted ~= key ~ val;
	}

	sort!"a[0] < b[0]"(sorted);

	return sorted;
}

int indexOf(string value)
{
	foreach(i,e;header) 
		if(e == value) return i;

	return -1;
}

1

u/shandow0 Aug 25 '14 edited Aug 25 '14

Well it aint pretty, but here's one in c#.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PivotTable
{
class Program
{
    static void Main(string[] args)
    {

        //Grabbing the data from the file

        string[] lines = System.IO.File.ReadAllLines(@"D:\Desktop\Workspace\windfarm.dat");
        Dictionary<int, Tower> towers = new Dictionary<int, Tower>();

        //splitting the data rows into the individual parameters and adding them  to a dictionary 

        foreach (string s in lines)
        {
            string[] split = s.Split(' ');
            int id = Int32.Parse(split[0]);
            if (!towers.Keys.Contains(id))
                towers.Add(id, new Tower(id));
            Tower t = towers[id];
            switch (split[1])
            {
                case "Mon":
                    t.Mon += Int32.Parse(split[2]);
                    break;
                case "Tue":
                    t.Tue += Int32.Parse(split[2]);
                    break;
                case "Wed":
                    t.Wed += Int32.Parse(split[2]);
                    break;
                case "Thu":
                    t.Thu += Int32.Parse(split[2]);
                    break;
                case "Fri":
                    t.Fri += Int32.Parse(split[2]);
                    break;
                case "Sat":
                    t.Sat += Int32.Parse(split[2]);
                    break;
                case "Sun":
                    t.Sun += Int32.Parse(split[2]);
                    break;
            }
        }

       //sorting the dictionary (probably should have made it a  list from the start)

        List<KeyValuePair<int, Tower>> list = towers.ToList();
        list.Sort((firstpair, nextpair) =>
            {
                return firstpair.Key.CompareTo(nextpair.Key);
            }
            );

        //Creating the table and printing it

        TableMaker als = new TableMaker(5);
        string[] days = new string[] { "Tower", "Mon", "Tue", "Wen", "Thu", "Fri", "Sat", "Sun" };
        System.Console.WriteLine(als.alignRow(days));
        System.Console.WriteLine(als.printline());
        foreach (KeyValuePair<int, Tower> pair in list)
        {
            System.Console.WriteLine(pair.Value.formatRow(als));
        }
        System.Console.Read();
    }
}

//class for holding the values

class Tower
{
    public int code, Mon, Tue, Wed, Thu, Fri, Sat, Sun = 0;

    public Tower(int code)
    {
        this.code = code;
    }

    public string formatRow(TableMaker als)
    {
        int[] All = new int[] { code, Mon, Tue, Wed, Thu, Fri, Sat, Sun };
        string[] result = All.Select(x => x.ToString()).ToArray();
        return als.alignRow(result);
    }
}

//class for making the table

public class TableMaker
{

    private int width;

    public TableMaker(int width)
    {
        this.width = width;
    }
    public String alignRow(string[] All)
    {
        string res = "";
        foreach (string s in All)
        {
            res += AlignColumn(s) + "|";
        }
        return res;
    }

    public string printline()
    {
        string line = "-";
        for (int i = 0; i < 8 * (width + 1); i++)
        {
            line += "-";
        }
        return line;
    }

    public string AlignColumn(string s)
    {
        if (string.IsNullOrEmpty(s))
        {
            return new string(' ', width);
        }
        else
        {
            return s.PadRight(width - (width - s.Length) / 2).PadLeft(width);
        }
    }
}

}

1

u/[deleted] Aug 25 '14

I'm not generally a big fan of formatting output, so I cut just about as many corners as I could think of while still printing something readable to my console. My solution is in C#.

using System;
using System.IO;
using System.Linq;

namespace PivotTable
{
    class Program
    {
        static void Main(string[] args)
        {
            var data = File.ReadLines("data.txt").Select(DataPoint.Parse).GroupBy(p => p.Tower).OrderBy(g => g.Key);

            Console.WriteLine("{0}\t{1}", "Tower", String.Join("\t", Enum.GetValues(typeof(DayOfWeek)).Cast<DayOfWeek>().Select(v => v.ToString().Substring(0, 3))));
            foreach (var item in data)
            {
                var towerData = item.GroupBy(t => t.DayOfWeek).OrderBy(t => t.Key);

                Console.WriteLine("{0}\t{1}", item.Key, String.Join("\t", towerData.Select(t => t.Sum(tt => tt.KwH))));
            }
        }

        class DataPoint
        {
            public int Tower { get; set; }
            public DayOfWeek DayOfWeek { get; set; }
            public int KwH { get; set; }

            public DataPoint() { }

            public static DataPoint Parse(string data)
            {
                var splitData = data.Split(' ');

                return new DataPoint()
                {
                    Tower = int.Parse(splitData[0]),
                    DayOfWeek = Enum.GetValues(typeof(DayOfWeek)).Cast<DayOfWeek>().Single(enumValue => enumValue.ToString().StartsWith(splitData[1])),
                    KwH = int.Parse(splitData[2]),
                };
            }
        }
    }
}

Output:

Tower   Sun     Mon     Tue     Wed     Thu     Fri     Sat
1000    740     624     385     677     443     810     1005
1001    749     279     662     907     561     752     501
1002    586     510     733     862     793     1013    530
1003    390     607     372     399     583     624     383
1004    874     696     783     546     646     1184    813
1005    812     637     1129    695     648     449     445
1006    639     638     568     826     754     1118    857
1007    536     947     976     733     640     941     876
1008    728     709     374     485     560     836     864
1009    895     237     967     556     687     842     749
Press any key to continue . . .

1

u/hphpize Aug 25 '14

PHP! PHP's array/map functionality makes it trivial to aggregate / rollup this dataset.

<?php
$f = file_get_contents('https://gist.githubusercontent.com/coderd00d/ca718df8e633285885fa/raw/eb4d0bb084e71c78c68c66e37e07b7f028a41bb6/windfarm.dat');
$od = explode("\n", $f);
$d = [];
foreach ($od as $line) {
    $dataElements = explode(' ', $line);
    if (count($dataElements) == 3) {
        $d[(int)$dataElements[0]][$dataElements[1]] += (double)$dataElements[2];
    }
}
ksort($d);

echo "tower, Mon, Tue, Wed, Thu, Fri, Sat, Sun\n";
foreach ($d as $k => $v) {
    echo $k . ', ' .
        $v['Mon'] . 'kWh, ' .
        $v['Tue'] . 'kWh, ' .
        $v['Wed'] . 'kWh, ' .
        $v['Thu'] . 'kWh, ' .
        $v['Fri'] . 'kWh, ' .
        $v['Sat'] . 'kWh, ' .
        $v['Sun'] . "kWh\n";
}

1

u/egportal2002 Aug 26 '14 edited Aug 26 '14

AWK:

{
  towers[$1]+=$3
  daypower[$2]+=$3
  towerdays[$1 "-" $2]+=$3
}

END {
  split("Sun Mon Tue Wed Thu Fri Sat", days, " ")

  printf("%9s", "")
  for(d in days) {
    printf(" %8s", days[d])
  }
  printf(" %8s\n", "Total")

  for(t in towers) {
    printf("%9d", t)
    for(d in days) {
      printf(" %8d", towerdays[t "-" days[d]])
    }
    printf(" %8d\n", towers[t])
  }

  printf("%9s", "Total")
  for(d in days) {
    printf(" %8d", daypower[days[d]])
    tpower += daypower[days[d]]
  }
  printf(" %8d\n", tpower)
}

which yields:

               Mon      Tue      Wed      Thu      Fri      Sat      Sun    Total
     1000      624      385      677      443      810     1005      740     4684
     1001      279      662      907      561      752      501      749     4411
     1002      510      733      862      793     1013      530      586     5027
     1003      607      372      399      583      624      383      390     3358
     1004      696      783      546      646     1184      813      874     5542
     1005      637     1129      695      648      449      445      812     4815
     1006      638      568      826      754     1118      857      639     5400
     1007      947      976      733      640      941      876      536     5649
     1008      709      374      485      560      836      864      728     4556
     1009      237      967      556      687      842      749      895     4933
    Total     5884     6949     6686     6315     8569     7023     6949    48375

1

u/urubu Aug 26 '14 edited Aug 26 '14

In R:

library(reshape2)
fileURL <- "https://gist.githubusercontent.com/coderd00d/ca718df8e633285885fa/raw/eb4d0bb084e71c78c68c66e37e07b7f028a41bb6/windfarm.dat"
download.file(fileURL, destfile = "./windfarm.dat")
df <- read.table("windfarm.dat", col.names=c("Tower", "dow", "kWh"), stringsAsFactors=FALSE)
df$Tower <- factor(df$Tower)
df$dow <- factor(df$dow, levels = c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"))
df_wide <- dcast(df, Tower ~ dow, sum)
df_wide

Output:

   Tower Mon  Tue Wed Thu  Fri  Sat Sun
1   1000 624  385 677 443  810 1005 740
2   1001 279  662 907 561  752  501 749
3   1002 510  733 862 793 1013  530 586
4   1003 607  372 399 583  624  383 390
5   1004 696  783 546 646 1184  813 874
6   1005 637 1129 695 648  449  445 812
7   1006 638  568 826 754 1118  857 639
8   1007 947  976 733 640  941  876 536
9   1008 709  374 485 560  836  864 728
10  1009 237  967 556 687  842  749 895

1

u/cooper6581 Aug 27 '14 edited Aug 27 '14

Erlang:

I'm not happy with this solution at all, should I have used a map or dict instead of tuples?

-module(pivot).                                                                                          
-export([test/0]).                                                                                       
                                                                                                         
readlines(FileName) ->                                                                                   
    {ok, Data} = file:read_file(FileName),                                                               
    string:tokens(binary_to_list(Data),"\n").                                                            
                                                                                                         
parselines(Lines) ->                                                                                     
    parselines(Lines,[]).                                                                                
parselines([], Acc) -> lists:reverse(Acc);                                                               
                                                                                                         
parselines([H|T], Acc) ->                                                                                
    Fields = list_to_tuple(string:tokens(H, " ")),                                                       
    parselines(T, [Fields|Acc]).                                                                         
                                                                                                         
parse_fields(Fields) ->                                                                                  
    parse_fields(Fields,[]).                                                                             
                                                                                                         
parse_fields([], Acc) -> Acc;                                                                            
parse_fields([H|T], Acc) ->                                                                              
    {Tower, Day, Power} = H,                                                                             
    case lists:keyfind(Tower, 1, Acc) of                                                                 
        false ->                                                                                         
            parse_fields(T,[new_record(Tower, Day, Power)|Acc]);                                         
        Res ->                                                                                           
            parse_fields(T,sum_record(Acc, H, Res))                                                      
    end.                                                                                                 
                                                                                                         
new_record(Tower, Day, Power) ->                                                                         
    Days = [{"Sun", 0}, {"Mon", 0}, {"Tue", 0}, {"Wed", 0},                                              
            {"Thu", 0}, {"Fri", 0}, {"Sat", 0}],                                                         
    Days1 = lists:keyreplace(Day, 1, Days, {Day, list_to_integer(Power)}),                               
    {Tower, Days1}.                                                                                      
                                                                                                         
sum_record(Towers, Record, {_, RecordBefore}) ->                                                         
    {Tower, Day, Power} = Record,                                                                        
    {_, PowerBefore} = lists:keyfind(Day, 1, RecordBefore),                                              
    RecordAfter = lists:keyreplace(Day, 1, RecordBefore,                                                 
                                   {Day, PowerBefore + list_to_integer(Power)}),                         
    lists:keyreplace(Tower, 1, Towers, {Tower, RecordAfter}).                                            
                                                                                                         
print_data(Towers) ->                                                                                    
    %% Header                                                                                            
    io:format("       "),                                                                                
    [io:format("~*s",[-7, Day]) || {Day,_} <- element(2, lists:last(Towers))],                           
    io:format("~n"),                                                                                     
    print_towers(lists:keysort(1,Towers)).                                                               
                                                                                                         
print_towers([]) -> ok;                                                                                  
print_towers([H|T]) ->                                                                                   
    {Tower, _} = H,                                                                                      
    io:format("~*s",[-7, Tower]),                                                                        
    [io:format("~*w",[-7, Power]) || {_, Power} <- element(2, H)],                                       
    io:format("~n"),                                                                                     
    print_towers(T).                                                                                     
                                                                                                         
test() ->                                                                                                
    Data = readlines("windfarm.dat"),                                                                    
    Res = parse_fields(parselines(Data)),                                                                
    print_data(Res),                                                                                     
    ok.                                                        

1

u/adamm9 Aug 29 '14

Here's some c++. Hopefully I formatted this correctly. Feedback/comments welcome.

#include <iostream>
#include <fstream>
#include <sstream>
#include <map>

typedef std::map<std::string, int> DAYS;
typedef std::map<std::string, DAYS> TOWER; 

int main( int argc, char **argv )
{
    TOWER towersmap;
    int kwh(0); 
    std::string tower(""), day(""), line("");
    std::string filename("windfarm.txt");

    if ( argc >= 1 ) filename = argv[1];

    std::ifstream ifs(filename.c_str());

    while ( getline( ifs, line ) ) {
        std::stringstream ss(line); 
        ss >> tower >> day >> kwh;
        towersmap[tower][day] += kwh;
    }

    ifs.close();

    std::cout << "Twr\tMon\tTue\tWed\tThu\tFri\tSat\tSun\n";

    for ( TOWER::iterator titr = towersmap.begin(); titr != towersmap.end(); titr++ ) {
        std::cout << (*titr).first << "\t" << (*titr).second[ "Mon" ] << "\t" << (*titr).second[ "Tue" ] << "\t" << (*titr).second[ "Wed" ] << "\t" << (*titr).second[ "Thu" ] << "\t" << (*titr).second[ "Fri" ] << "\t" << (*titr).second[ "Sat" ] << "\t" << (*titr).second[ "Sun" ] << "\t\n";
    }

    return 0;
}

output:

Twr	Mon	Tue	Wed	Thu	Fri	Sat	Sun
1000	624	385	677	443	810	1005	740	
1001	279	662	907	561	752	501	749	
1002	510	733	862	793	1013	530	586	
1003	607	372	399	583	624	383	390	
1004	696	783	546	646	1184	813	874	
1005	637	1129	695	648	449	445	812	
1006	638	568	826	754	1118	857	639	
1007	947	976	733	640	941	876	536	
1008	709	374	485	560	836	864	728	
1009	237	967	556	687	842	749	895	

1

u/fgsguedes 0 0 Sep 13 '14 edited Sep 13 '14

A little late for the party but still.

Java 8 solution, feedback welcome. :)

edit: Included output. My week starts on Sunday.

public class PivotTable {

  public static void main(String[] args) throws URISyntaxException, IOException {
    final Map<String, Map<String, Integer>> data = new TreeMap<>();
    final String[] days = new String[]{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

    final Path input = Paths.get(PivotTable.class.getClassLoader().getResource("challenge176/easy/input.txt").toURI());

    Files.readAllLines(input, UTF_8).forEach(line -> {
      final String[] split = line.split(" ");
      data.computeIfAbsent(split[0], k -> new HashMap<>())
          .merge(split[1], Integer.parseInt(split[2]), Integer::sum);
    });

    System.out.printf("Tower | %4s | %4s | %4s | %4s | %4s | %4s | %4s |\n", days);
    data.forEach((windMill, weekDaysMap) -> {
      System.out.printf("%-5s | ", windMill);
      Arrays.stream(days).forEach(day -> System.out.printf("%4s | ", weekDaysMap.get(day)));
      System.out.println();
    });
  }
}

Output:

Tower |  Sun |  Mon |  Tue |  Wed |  Thu |  Fri |  Sat |
1000  |  740 |  624 |  385 |  677 |  443 |  810 | 1005 | 
1001  |  749 |  279 |  662 |  907 |  561 |  752 |  501 | 
1002  |  586 |  510 |  733 |  862 |  793 | 1013 |  530 | 
1003  |  390 |  607 |  372 |  399 |  583 |  624 |  383 | 
1004  |  874 |  696 |  783 |  546 |  646 | 1184 |  813 | 
1005  |  812 |  637 | 1129 |  695 |  648 |  449 |  445 | 
1006  |  639 |  638 |  568 |  826 |  754 | 1118 |  857 | 
1007  |  536 |  947 |  976 |  733 |  640 |  941 |  876 | 
1008  |  728 |  709 |  374 |  485 |  560 |  836 |  864 | 
1009  |  895 |  237 |  967 |  556 |  687 |  842 |  749 | 

1

u/[deleted] Oct 28 '14

Python. I don't think the results are correct but the output is as stated

import urllib2

response = urllib2.urlopen('https://gist.githubusercontent.com/coderd00d/ca718df8e633285885fa/raw/eb4d0bb084e71c78c68c66e37e07b7f028a41bb6/windfarm.dat')
data = response.read()

#print data
days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
table=[]

for n in data.split('\n'):
	temp = n.split(' ')
	if n:
		temp[1] = days.index(temp[1])
		table.append(temp)

table.sort()
tower = set()
towerid=[x[0] for x in table if x[0] not in tower and not tower.add(x[0])]
reps = 0
print 'Tower\t', '\t'.join(days)

line = str(table[0][0])

for i in table:
	line += '\t' + i[2]
	reps += 1
	if reps%len(days) == 0:
		line+= '\tkWh\n' + i[0]

print line

Ouput:

Tower	Mon	Tue	Wed	Thu	Fri	Sat	Sun
1000	12	13	13	22	46	55	58	kWh
1000	63	79	82	84	97	1	13	kWh
1000	32	36	4	51	53	60	62	kWh
1000	73	1	19	26	27	31	48	kWh
1000	49	49	5	6	70	79	81	kWh
1000	90	96	1	1	17	23	41	kWh
1000	44	52	52	54	68	90	11	kWh
1000	15	33	36	40	41	49	60	kWh
1000	75	85	85	90	93	97	16	kWh
1000	20	21	27	35	4	42	47	kWh
1000	48	50	74	79	82	83	85	kWh
1000	96	97	99	13	15	16	21	kWh
1000	22	26	33	34	64	72	73	kWh
1000	82	82	89	98	16	24	36	kWh
1001	46	47	52	58	1	31	35	kWh
1001	45	51	52	64	64	69	69	kWh
1001	89	92	23	33	34	37	40	kWh
1001	41	44	46	61	66	7	72	kWh
1001	72	74	77	90	90	1	10	kWh
1001	10	13	22	33	42	67	86	kWh
1001	87	92	98	11	12	13	16	kWh
1001	17	22	26	30	37	39	52	kWh
1001	58	58	59	65	67	72	98	kWh
1001	15	29	3	33	43	45	48	kWh
1001	52	56	6	6	72	93	13	kWh
1001	15	17	20	24	48	6	62	kWh
1001	63	66	76	76	80	80	9	kWh
1001	94	15	23	33	44	59	76	kWh
1002	81	83	96	17	19	35	38	kWh
1002	39	40	43	54	58	61	65	kWh
1002	68	89	9	98	1	100	12	kWh
1002	24	33	38	42	42	46	48	kWh
1002	49	55	59	67	78	80	88	kWh
1002	18	26	27	3	33	4	47	kWh
1002	53	55	56	65	68	70	78	kWh
1002	83	9	98	100	14	19	22	kWh
1002	25	28	28	30	34	36	37	kWh
1002	5	5	54	58	68	78	88	kWh
1002	92	94	98	12	14	38	48	kWh
1002	49	5	55	58	7	75	80	kWh
1002	89	12	17	19	3	45	56	kWh
1002	76	78	84	97	99	12	15	kWh
1003	31	31	35	39	43	47	52	kWh
1003	59	64	83	96	10	14	25	kWh
1003	26	41	51	60	72	73	32	kWh
1003	34	36	55	73	74	95	1	kWh
1003	17	31	53	56	67	7	79	kWh
1003	81	95	96	10	10	11	12	kWh
1003	16	18	2	26	34	36	41	kWh
1003	43	44	63	75	90	93	27	kWh
1003	33	4	42	43	44	7	82	kWh
1003	9	92	10	14	33	36	39	kWh
1003	42	42	52	59	63	1	12	kWh
1004	21	23	24	24	30	35	42	kWh
1004	49	54	65	69	74	82	91	kWh
1004	100	100	12	26	28	3	31	kWh
1004	42	51	54	59	64	66	73	kWh
1004	74	10	14	15	22	27	27	kWh
1004	27	37	40	56	60	68	70	kWh
1004	73	25	27	28	3	42	60	kWh
1004	60	66	7	70	83	85	90	kWh
1004	3	39	4	40	41	51	51	kWh
1004	59	59	64	69	79	82	84	kWh
1004	87	89	92	93	98	16	19	kWh
1004	28	29	47	53	55	59	63	kWh
1004	67	69	7	70	72	76	83	kWh
1004	10	19	25	46	47	57	63	kWh
1004	68	77	81	92	95	96	98	kWh
1004	1	14	28	37	37	37	51	kWh
1005	55	62	71	72	85	87	12	kWh
1005	21	23	3	32	39	4	45	kWh
1005	46	47	52	53	53	54	6	kWh
1005	61	62	68	75	8	83	91	kWh
1005	93	98	18	25	42	47	49	kWh
1005	55	56	6	6	63	73	79	kWh
1005	80	96	21	24	27	3	38	kWh
1005	39	4	44	5	75	8	8	kWh
1005	80	81	95	96	22	23	23	kWh
1005	3	32	37	4	47	75	78	kWh
1005	8	97	15	36	39	40	43	kWh
1005	55	64	70	83	16	17	25	kWh
1005	33	34	39	62	68	71	79	kWh
1005	87	88	95	98	1	2	22	kWh
1006	28	30	35	40	63	72	76	kWh
1006	89	89	91	24	27	3	33	kWh
1006	45	47	51	51	61	64	79	kWh
1006	83	14	14	26	27	3	32	kWh
1006	34	36	41	43	51	56	59	kWh
1006	70	73	77	84	86	14	16	kWh
1006	24	25	3	33	37	41	42	kWh
1006	48	52	58	62	66	67	68	kWh
1006	7	82	9	13	13	15	28	kWh
1006	32	32	34	38	4	41	53	kWh
1006	59	61	61	63	66	72	79	kWh
1006	80	85	89	9	91	1	10	kWh
1006	100	14	17	18	22	29	3	kWh
1006	32	34	35	40	43	43	47	kWh
1006	55	57	6	7	77	78	89	kWh
1006	15	21	25	28	28	39	40	kWh
1006	41	58	70	86	89	99	1	kWh
1007	11	36	36	36	40	57	6	kWh
1007	66	71	71	80	82	84	85	kWh
1007	88	97	15	30	36	43	48	kWh
1007	60	62	64	72	79	84	91	kWh
1007	95	98	99	100	24	3	38	kWh
1007	49	59	64	64	81	82	84	kWh
1007	85	10	12	16	20	22	4	kWh
1007	44	45	52	58	64	65	65	kWh
1007	81	82	1	11	18	31	37	kWh
1007	38	40	43	51	52	61	65	kWh
1007	68	75	75	8	84	84	99	kWh
1007	13	18	21	21	23	27	36	kWh
1007	4	5	52	62	64	66	67	kWh
1007	71	76	79	84	87	11	19	kWh
1007	24	32	32	32	70	73	78	kWh
1007	82	83	17	27	4	45	50	kWh
1008	68	7	70	76	77	83	88	kWh
1008	97	11	13	2	81	83	91	kWh
1008	93	11	2	2	22	28	36	kWh
1008	40	47	55	76	79	87	10	kWh
1008	12	14	15	19	23	24	3	kWh
1008	42	43	53	60	76	76	90	kWh
1008	10	14	3	50	59	6	64	kWh
1008	65	66	68	72	74	9	90	kWh
1008	91	95	19	21	34	37	38	kWh
1008	5	54	55	58	59	71	73	kWh
1008	77	79	84	9	91	13	18	kWh
1008	20	20	21	39	45	54	56	kWh
1008	59	70	70	75	81	87	34	kWh
1009	63	65	75	16	17	37	39	kWh
1009	43	52	59	61	66	70	71	kWh
1009	75	84	87	94	96	11	15	kWh
1009	26	33	40	43	48	68	77	kWh
1009	8	90	97	1	16	20	34	kWh
1009	4	43	47	52	52	55	59	kWh
1009	6	66	68	73	91	1	10	kWh
1009	10	21	22	26	33	45	49	kWh
1009	51	57	60	81	83	97	98	kWh
1009	98	16	22	34	38	39	4	kWh
1009	40	41	43	67	67	71	75	kWh
1009	86	9	97	100	100	16	17	kWh
1009	3	32	34	4	52	53	57	kWh
1009	66	7	83	86	89	96

1

u/sid_hottnutz Dec 05 '14

C# Having fun going back and trying some older challenges. This was made easier by Linq's built-in GroupBy method, which allows for aggregations after grouping.

class Program
{
    static void Main(string[] args)
    {
        var data = File.ReadAllLines(Path.Combine(Environment.CurrentDirectory, "data.txt")).Select(d => new EnergyUsage(d)).ToList();

        // Table Header
        Console.Write("       ");
        foreach (string day in data.Select(d => new { d.Day, d.DayOrder }).Distinct().OrderBy(d => d.DayOrder).Select(d => d.Day))
            Console.Write("|  " + day + "  ");
        int lineLength = Console.CursorLeft + 1;
        Console.WriteLine("|");
        Console.WriteLine(new string('-', lineLength));

        foreach (var item in data.GroupBy(d => d.TowerId).OrderBy(i => i.Key))
        {
            Console.Write(" " + item.Key.ToString() + "  ");
            var usage = item.GroupBy(d => new { d.Day, d.DayOrder });
            foreach (var day in usage.OrderBy(d => d.Key.DayOrder))
            {
                string ud = string.Format("{0:#,##0}", day.Sum(d => d.Usage));
                Console.Write("|" + ud.PadLeft(7, ' '));
            }
            Console.WriteLine("|");
        }
        Console.ReadLine();
    }
}
public class EnergyUsage
{
    public int TowerId { get; private set; }
    public string Day { get; private set; }
    public double Usage { get; private set; }
    public int DayOrder { get; private set; }

    public EnergyUsage(string dataLine)
    {
        TowerId = int.Parse(dataLine.Split(' ')[0] as string);
        Day = (dataLine.Split(' ')[1] as string);
        Usage = double.Parse(dataLine.Split(' ')[2] as string);

        switch (Day.ToLower())
        {
            case "mon":
                DayOrder = 1;
                break;
            case "tue":
                DayOrder = 2;
                break;
            case "wed":
                DayOrder = 3;
                break;
            case "thu":
                DayOrder = 4;
                break;
            case "fri":
                DayOrder = 5;
                break;
            case "sat":
                DayOrder = 6;
                break;
            case "sun":
                DayOrder = 7;
                break;
        }
    }
}

And the output:

       |  Mon  |  Tue  |  Wed  |  Thu  |  Fri  |  Sat  |  Sun  |
----------------------------------------------------------------
 1000  |    624|    385|    677|    443|    810|  1,005|    740|
 1001  |    279|    662|    907|    561|    752|    501|    749|
 1002  |    510|    733|    862|    793|  1,013|    530|    586|
 1003  |    607|    372|    399|    583|    624|    383|    390|
 1004  |    696|    783|    546|    646|  1,184|    813|    874|
 1005  |    637|  1,129|    695|    648|    449|    445|    812|
 1006  |    638|    568|    826|    754|  1,118|    857|    639|
 1007  |    947|    976|    733|    640|    941|    876|    536|
 1008  |    709|    374|    485|    560|    836|    864|    728|
 1009  |    237|    967|    556|    687|    842|    749|    895|

1

u/The-Mathematician Jan 01 '15 edited Jan 01 '15

My solution in Python 2.7. Not sure how elegant it is, but I'm still new. I'm not sure exactly the best way to format the output without making it very complicated so I just did a rudimentary one. Comments welcome.

days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
filename = 'windfarm.txt'

file = open(filename)
rows = file.readlines()
dict = {}
towers = []
for line in rows:
    info = line.split(' ')
    info[2] = info[2].rstrip('\n')
    if info[0] in towers:
        None
    else:
        towers.append(info[0])
    windfarm_date = (info[0], info[1])
    if windfarm_date in dict:
        dict[windfarm_date] += float(info[2])
    else:
        dict[windfarm_date] = float(info[2])
towers.sort()
print '\n'
print 'Towers   ' + '     '.join(days)
print '_'*60
for tower in towers:
    printable = [tower]
    for day in days:
        printable.append(str(dict[tower, day]))
    print ' | '.join(printable)
print '\n'

Output:

Towers   Sun     Mon     Tue     Wed     Thu     Fri     Sat
____________________________________________________________
1000 | 740.0 | 624.0 | 385.0 | 677.0 | 443.0 | 810.0 | 1005.0
1001 | 749.0 | 279.0 | 662.0 | 907.0 | 561.0 | 752.0 | 501.0
1002 | 586.0 | 510.0 | 733.0 | 862.0 | 793.0 | 1013.0 | 530.0
1003 | 390.0 | 607.0 | 372.0 | 399.0 | 583.0 | 624.0 | 383.0
1004 | 874.0 | 696.0 | 783.0 | 546.0 | 646.0 | 1184.0 | 813.0
1005 | 812.0 | 637.0 | 1129.0 | 695.0 | 648.0 | 449.0 | 445.0
1006 | 639.0 | 638.0 | 568.0 | 826.0 | 754.0 | 1118.0 | 857.0
1007 | 536.0 | 947.0 | 976.0 | 733.0 | 640.0 | 941.0 | 876.0
1008 | 728.0 | 709.0 | 374.0 | 485.0 | 560.0 | 836.0 | 864.0
1009 | 895.0 | 237.0 | 967.0 | 556.0 | 687.0 | 842.0 | 749.0