Вот способ:
//Construct dataframe
val df = sc.parallelize(Seq((1,"{\"name\":\"Anne\",\"Age\":\"12\",\"country\":\"Denmark\"}"),
(2, "{\"name\":\"Zen\",\"Age\":\"24\"}"),
(3, "{\"name\":\"Fred\",\"Age\":\"20\",\"country\":\"France\"}"),
(4, "{\"name\":\"Mona\",\"Age\":\"18\",\"country\":\"Denmark\"}"))).toDF("ID", "details_Json")
df.show
+---+--------------------+
| ID| details_Json|
+---+--------------------+
| 1|{"name":"Anne","A...|
| 2|{"name":"Zen","Ag...|
| 3|{"name":"Fred","A...|
| 4|{"name":"Mona","A...|
+---+--------------------+
import org.apache.spark.sql.types.{StructType, StructField, StringType, IntegerType}
val struct =
StructType(
StructField("name", StringType, true) ::
StructField("Age", StringType, true) ::
StructField("country", StringType, true) :: Nil)
val df2 = df.withColumn("details_Struct", from_json($"details_Json", struct)).withColumn("country", $"details_Struct".getField("country")).filter($"country".equalTo("Denmark")).drop("country", "details_Struct")
df2.show
+---+--------------------+
| ID| details_Json|
+---+--------------------+
| 1|{"name":"Anne","A...|
| 4|{"name":"Mona","A...|
+---+--------------------+
Ответ выше в Apache Spark 2.3.1. Какую версию вы используете? В версии 2.4.1 есть функция schema_of_json
, которая автоматически выводит схему. Вы можете также проверить это. https://spark.apache.org/docs/latest/api/scala/index.html#org.apache.spark.sql.functions$@schema_of_json (JSON: String): org.apache.spark.sql .Column
Блоки действительно хороши:
my_array.each { |element| print element }
#...
File.open("foo.txt") do |file|
# do stuff with file
end
Это - довольно маленькая, почти незначительная функция, но мне действительно нравится эта конструкция:
var ||= "default"
Это устанавливает var
к значению по умолчанию ("default"
) если var
еще не был установлен или сохраняет текущее значение var
если это уже было установлено. Мне нравится компактный синтаксис.
В том же направлении я могу сделать что-то вроде этого:
new_val = old_val || "default"
установить значение по умолчанию, также.
В целом мне нравится, как все выражения Ruby возвращают значение, таким образом, я могу использовать операторы как ||
записать короткие, компактные операторы.
Мне нравится способность вызвать функции без круглых скобок и функции, возвращая последнее оцененное выражение.
Первый сохраняет много ненужных круглых скобок и делает код легче читать.
Последний может стать довольно сбивающим с толку иногда, но это является большим для короткого (особенно логичный) функции.
Счетный! Некоторые примеры того, почему это является потрясающим.
a = ['foo', 'bar', 'baz']
a.delete_if {|i| i =~ /^f/ }
# vs
new = []
a.each do |i|
if i !~ /^f/
new << i
end
end
a.select {|i| i =~ /^f/ }
# vs
new = []
a.each do |i|
if i =~ /^f/
new << i
end
end
a.detect {|i| i =~ /^f/ }
# vs
a.each do |i|
if i =~ /^f/
return i
end
end
Очень хорошо смочь сказать непосредственно, чего Вы хотите достигнуть с 'выбором', 'обнаружьте', 'delete_if' и так далее, вместо цикличного выполнения и выполнения всего вручную. Счетный помогает ввести, и легче понять при чтении кода.
То, что классы являются объектами, и новый метод на классе:
c = Array
a = c.new()
И мне нравится как патронажные работы. Это называет === на каждом значении случая и возвращает значение:
if(0 <= age && age <= 10){
x = "kid"
}else if(10 <= age && age <= 80)
x = "person"
}else if(80 <= age && age <= 99)
x = "old"
}else{
x = "???"
}
=>
x = case age
when 0..10: "kid"
when 10..80: "person"
when 80..99: "old"
default: "???"
end
Это работает потому что диапазоны (0.. 10), имеют === метод, который проверяет, находится ли что-то в диапазоне: (5.. 10) === 6 ==> верный. Regexes поддерживают === также, таким образом, можно сделать:
case str
when /regex1/: ...
when /regex2/: ...
...
end
Можно даже записать === метод для собственных объектов.
Другая хорошая функция: удостовериться. Это похоже наконец, но имеет краткий синтаксис в Ruby. Можно использовать его, когда у Вас есть что-то вроде этого:
def foo(x)
return_value = bar(x)
dosomething(x)
return return_value
end
=>
def foo(x)
bar(x)
ensure
dosomething(x)
end
вопросительный знак / соглашение о присвоении имен восклицательного знака
часто никакой parens, необходимый после вызова метода
закрытия
rubygems
Хорошо, я предполагаю, что это - некоторые избранное :)
Моей любимой функцией прямо сейчас (после контакта с Soap4R недавно) является, вероятно, самоанализ, это доступно. Эти два метода особенно полезны:
public_methods - Возвращает список всех методов на объекте. Супер полезный от отладчика или irb, когда Вы пытаетесь выяснить то, что можно сделать к чему-то. (Второй
instance_variables - Возвращает список всех переменных экземпляра на объекте.
Существуют все виды другого хорошего материала здесь: http://www.ruby-doc.org/core/classes/Object.html
Открытые классы являются одним из моего избранного. Например, это:
# try.rb
class TryObjectMock
public_instance_methods.reject { |x| x =~ /^__/ }.each { |x| undef_method(x) }
def method_missing(symbol, *args)
end
end
class Object
def try
self.nil? ? TryObjectMock.new : self
end
end
делает код, который обрабатывает nil
способные более ясные объекты:
irb(main):001:0> require 'try'
irb(main):002:0> puts "5".try.to_i
5
irb(main):003:0> puts nil.try.to_i
nil
irb(main):004:0> puts [1, 2].try.find { |x| x == 2 }.try + 3
5
irb(main):005:0> puts [1, 2].try.find { |x| x == 3 }.try + 3
nil
irb(main):006:0> puts nil.try.find { |x| x == 3 }.try + 3
nil
irb(main):007:0>
Это избегает большого количества из if-else
s:
irb(main):007:0> a = [1, 2]
irb(main):008:0> puts(if a
irb(main):009:2> if b = a.find { |x| x == 2 }
irb(main):010:3> b + 3
irb(main):011:3> end
irb(main):012:2> end)
5
irb(main):013:0> c = "5"
irb(main):014:0> puts(c ? c.to_i : nil)
5
Прием работает путем определения метода try
для каждого класса в объектном пространстве. Когда это звонило, это возвращает специальный объект, когда объект nil
(nil
экземпляр NilClass
, который является подклассом Object
!) или сам объект иначе. Тот специальный объект просто возвращается nil
для каждого названного метода (через пустое method_missing
реализация). Обратите внимание, что это также работает на операторы, так как они - методы объекта левой стороны.
Операторы if
также являются выражениями, поэтому последняя строка блока возвращает значение. Допускается код вроде:
my_var = if some_var.is_true?
if some_other_var > 8
1
else
23
end
else
5
end
Здесь my_var
будет иметь значение 1, 23 или 5, в зависимости от того, как оцениваются условия.
Логические операторы для не логических значений.
&&
и ||
Оба возвращают значение последнего вычисленного выражения. Благодаря короткому замыканию они создают удобные короткие пути. Они рассматривают любое значение, отличное от nil или false, как истинное для целей обнаружения короткого замыкания.
Пример:
a = b || c
Присваивает значение c переменной a, только если b равно нулю или false.
a = b && c
Присваивает значение of c для a, только b не является nil или false, в противном случае присваивается b.
Такое поведение объясняет уже упомянутый || =
.
Однако оператор && =
не получает такой же любви.
string &&= string + "suffix"
эквивалентно
if string
string = string + "suffix"
end
Это очень удобно для деструктивных операций, которые не должны выполняться, если переменная не определена.
Я не мог выбрать только один, но первое, что пришло в голову, было splat: *
По сути, он позволяет вам превращать массив в список аргументов и наоборот , позволяя делать такие вещи:
odds = [1, 3, 7]
evens = [2, 4, 6]
case 4
when *odds then "odd!"
when *evens then "even!"
end
# => "even!"
arr = [ :a, 1, :b, :2 ]
Hash[*arr] # => { :a => 1, :b => 2 }
a, b, c = *(1..3)
puts a # => 1
puts b # => 2
puts c # => 3
a = 1, *[2, 3] # => [1, 2, 3]
# And of course...
def f(*args)
puts args
end
f 1, 2, 3 # => [1, 2, 3]