teratailの回答まとめ
自分がteratailで回答したもののうち、役に立ちそうなものをまとめておきます。
単純な質問と回答はteratailでも見れるので「単独で読んでも得られるものがある」「そのトピックでよく見受けられる質問に対する回答」を基準にしています。
間違いなどがあればteratail上で各回答のコメント欄にコメントいただけると助かります。
もうすでに解決済みかもしれませんが、何かの役に立てばと思い、回答します。
畳み込み関数について
畳み込み関数というのは、ざっくりいうと「リストの要素に順番に関数を適用してその結果を蓄積し、最後に蓄積した結果を返す」関数です。
ある整数リストの要素をすべて足した結果を返すsum
関数を考えてみましょう。
リストをxs
、適用する関数を+
(整数の足し算)とすると、こんなイメージです。
let sum xs =
let acc = 0 (* 初期値は 0 *)
let x = List.nth xs 1 (* リストから1つ目の要素を取り出す *)
let acc = acc + x (* acc と要素 x に関数(ここでは足し算)を適用した結果を acc に覚えておく *)
let x = List.nth xs 2 (* リストから2つ目の要素を取り出す *)
let acc = acc + x (* acc と要素 x に関数を適用した結果を acc に覚えておく *)
... (* これをリストの要素の数だけ繰り返す *)
acc (* 最後に acc を返す *)
このような「リストからある値に『畳み込む』関数」はよく書きますので、標準のList
モジュールにすでに用意されています。
val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
val fold_right: ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b
引数には「適用する関数」「初期値」「リスト」を渡します。fold_left
とfold_right
で引数の順番が逆になっていますので注意です。
fold_left
はリストの左から(つまりリストの1つ目の要素、2つ目の要素……の順に)、fold_right
は右から(つまりリストの「最後から1つ目」の要素、「最後から2つ目の要素」……の順に)関数を適用していきます。
リストの最大要素を返す関数
ではfold_right
を用いてリストの最大要素を返す関数を書いてみましょう(fold_left
でも同様です)。
まず、欲しい関数の型は以下です。
わかりやすいよう、整数のリストのみ扱うことにしましょう。
val max_of_int_list: int list -> int
リストを引数に渡すと最大の要素が返ってきます。
let max_of_int_list xs =
let init = List.hd x in (* 初期値はリストの最初の要素とします *)
List.fold_right (fun acc x ->
(* acc(つまり今までで最大の要素)よりも x が大きければ acc を x とします *)
if acc < x
then x
else acc
) xs init
これで完成です。
整数以外にも対応させたければ「ある要素が別の要素より大きいかどうか比較する関数」を引数に追加し、以下のようにすればよいでしょう。
val max_of_list: ('a -> 'a -> int) -> 'a list -> 'a
let max_of_list cmp xs =
let init = List.hd x in (* 初期値はリストの最初の要素とします *)
List.fold_right (fun acc x ->
(* cmp a b は a < b なら負数、a > b なら正数、a = b なら 0 を返す関数 *)
if (cmp acc x) < 0
then x
else acc
) xs init
注意点
List
モジュールのfold_right
は末尾再帰ではありませんので、大きなリストに対して使うとスタックオーバーフローする可能性があります。そのときは何回かに分けるか、末尾再帰に書き直しましょう。
fold_left
は末尾再帰です。
また、上記のmax_of_int_list
やmax_of_list
は初期値として最初の要素を渡しているため、最初の1回の比較は無駄ですし、空リストに対しては例外が発生します。わかりやすさ優先としたので、気になるようなら書き直してください。
すでに解決済みかもしれませんが、同じような方がいるかもしれないので回答します。
function
について
OCamlのfunction
キーワードはlet f x = match x with ...
のショートハンドです。
そのため、let rec string_of_exp v = function ...
の引数v
は不要です。
ご参考までに、以下のf
とg
は同じです。
let f x =
match x with
| None -> "None"
| Some v -> v
let g = function
| None -> "None"
| Some v -> v
string_of_exp
を書く
以上の話を踏まえ、関数string_of_exp
の型を考えます。
欲しい関数はデータ型exp
をstring
に変換する関数ですから、以下のような型の関数になります。
val string_of_exp : exp -> string
では、各パターンマッチでstring
を返すように関数を書いていきましょう。
let rec string_of_exp = function
| Num n -> (* n: int を string に変換する式 *)
| Var v -> (* v: string を string に変換する式 *)
| Add (x, y) -> (* x: exp, y: exp を string に変換する式 *)
| Mul (x, y) -> (* x: exp, y: exp を string に変換する式 *)
引数がNum
のときはstring_of_int
でstringに変換します。
let rec string_of_exp = function
| Num n -> string_of_int n
引数がVar
のときは値がstring
ということでおそらく変数名でしょうから、そのまま返します。
let rec string_of_exp = function
| Var v -> v
引数がAdd
のときは(値 + 値)
と表示するか足し算した結果を表示するかによりますが、今回は「exp 型の数式の文字列表現」ということなので、前者とします。
let rec string_of_exp = function
| Add (x, y) -> Printf.sprintf "(%s + %s)" (string_of_exp x) (string_of_exp y)
引数がMul
のときもAdd
と同様に(値 * 値)
と表示することにします。
let rec string_of_exp = function
| Mul (x, y) -> Printf.sprintf "(%s * %s)" (string_of_exp x) (string_of_exp y)
以上をまとめて、string_of_exp
は以下のようになります。
let rec string_of_exp = function
| Num n -> string_of_int n
| Var v -> v
| Add (x, y) -> Printf.sprintf "(%s + %s)" (string_of_exp x) (string_of_exp y)
| Mul (x, y) -> Printf.sprintf "(%s * %s)" (string_of_exp x) (string_of_exp y)
参考情報
以下にpuroさんが書かれたコードにでてくるいくつかの式の型を書いておきます。
int_of_exp
やmake_sum
がどういった関数なのか不明だったので、一部は関数名から想像した型を前提に書いています。
string_of_int n (* string *)
int_of_exp x (* int_of_exp: exp -> int なら int *)
(x+y) (* x: exp, y: exp なので対応する + が定義されておらず、型エラー *)
make_sum (...) (* make_sum: int list -> int なら int *)
注意点
わかりやすさを優先し、以上のstring_of_exp
は末尾再帰になっていません。
大きな式を文字列に変換しようとするとスタックオーバーフローする可能性があるので、そのときは何回かに分けて呼び出すか、関数を末尾再帰に書き直してください。
以上、お役に立てれば幸いです。
array_map()
とimplode()
を使う方法
1. array_map()
で$items1
を<a 〜>〜</a>
という文字列の配列に変換した後、implode()
で「、」を挿入し、出力する方法です。
個人的にはこちらのほうが素直な解法かと思います。
echo implode("、", array_map(
fn($value) => '<a href='.$url.'/meta?key=team&value='.$value.'>'.$value.'</a>',
$items1
))
foreach
を使う方法
2. foreach
で繰り返すときに要素のインデックスも取得するようにし、最後の要素でなければ「、」を出力する方法もあります。
$last_index = count($items1) - 1;
foreach($items1 as $index => $value) {
echo '<a href='.$url.'/meta?key=team&value='.$value.'>'.$value.'</a>';
if ($index != $last_index) { // 最後の要素でない場合
echo '、'
}
}
参考
Google Cloud Text-to-Speechを使いましょう。
base64で音声データが帰ってきますのでmp3
ファイルにデコードすれば出来上がりです。
const textToSpeech = require('@google-cloud/text-to-speech');
const fs = require('fs');
const util = require('util');
const client = new textToSpeech.TextToSpeechClient();
const text = 'こんにちは';
const outputFile = 'output.mp3';
const request = {
input: {text: text},
voice: {languageCode: 'ja-JP', ssmlGender: 'FEMALE'},
audioConfig: {audioEncoding: 'MP3'},
};
const [response] = await client.synthesizeSpeech(request);
const writeFile = util.promisify(fs.writeFile);
await writeFile(outputFile, response.audioContent, 'binary');
console.log(`Audio content written to file: ${outputFile}`);
PyrhonのTkinterをつかってグラフを画面の真ん中に表示させたい | teratail
grid
を中央に表示するには、grid()
で配置する要素の親要素にgrid_anchor(tkinter.CENTER)
を使います。
import tkinter as tk
root = tk.Tk()
# gridを中央に寄せる
root.grid_anchor(tk.CENTER)
frame = tk.Frame(root)
frame.grid() # 親要素rootのgrid(row=0, column=0)に配置
イメージとしては、親要素がgrid
という要素を持っていて、その中にframe
やborder
を配置するイメージです。
そして、そのgrid
自体の配置場所を中央にするメソッドがgrid_anchor()
です。
grid()
のanchor
引数は「grid
セル内のどこに要素を配置するか」を決めるものなので、子要素が1つしか無くgrid
自体を中央に持ってきたい今回の場合は指定しても見た目の変化がありません。
ご質問のコードでは一つの要素が一つの子要素を持つので、root
にgrid_anchor(tkinter.CENTER)
を設定すればあとは設定しなくてもよいでしょう。
なお、root.geometry('700 x 500')
はエラーが出るので、修正しました。
import tkinter as tk
root = tk.Tk()
root.title("Application")
root.resizable(width=False,height=False)
root.geometry('700x500')
# gridを中央に配置
root.grid_anchor(tk.CENTER)
frame = tk.Frame(root, width=700, height=300, bg="red")
frame.grid()
border = tk.LabelFrame(frame, text="Form", fg='white', bg='#444', relief=tk.FLAT)
border.grid()
innerBox = tk.Frame(border, width=300, height=100)
innerBox.grid()
root.mainloop()
ではなぜ質問にあるような状態になったのでしょうか。
それぞれどうなっているのかを確認してみましょう。
まずご質問にある1つ目のコードです。
import tkinter as tk
# 1. メインウィンドウの作成
root = tk.Tk()
root.title("Application")
root.resizable(width=False,height=False)
root.geometry('700x500')
frame = tk.Frame(root, width=700, height=300, bg="red")
frame.grid() # これはrootのgrid(row=0, column=0)に配置される
border = tk.LabelFrame(frame, text="Form", fg='white', bg='#444', relief=tk.FLAT)
border.grid() # これはframeのgrid(row=0, column=0)に配置される
innerBox = tk.Frame(border, width=300, height=100)
innerBox.grid() # これはborderのgrid(row=0, column=0)に配置される
root.mainloop()
このコードではroot
にframe
をgrid
で配置し、frame
内にborder
をgrid
で配置しています。
このときroot
のgrid
は上部に表示され、grid
のサイズは子要素に合わせられます。
これはframe
のgrid
も同様です。
すると、border
はframe
のgrid
内の上部、frame
のgrid
はframe
内の上部、frame
はroot
内のgrid
の上部、そしてroot
のgrid
はroot
の上部、といった配置になり、それぞれのgrid
のサイズは子要素に合わせられますので、結果的にborder
が左上に配置されたように見えます。
一方、ご質問の2つ目のコードではframe
とborder
がroot
にgrid
で配置されています。
border.grid()
と「どのセルに配置するか」を指定していませんので、frame
の下のセルに追加されることに注意です。
import tkinter as tk
root = tk.Tk()
root.title("Application")
root.resizable(width=False,height=False)
root.geometry('700x500')
frame = tk.Frame(root, width=700, height=300, bg="#000080")
frame.grid() # これはrootのgrid(row=0, column=0)に配置される
border = tk.LabelFrame(root, text="Form", fg='white', bg='#444', relief=tk.FLAT)
border.grid() # これはrootのgrid(row=1, column=0)に配置される
innerBox = tk.Frame(border, width=300, height=100)
innerBox.grid() # これはborderのgrid(row=0, column=0)に配置される
root.mainloop()
root
のgrid
はroot
の上部に表示され、その内部にframe
とborder
が縦に配置されます。
このときgrid
のセルの大きさは一番大きいセルに合わせられますのでframe
の大きさになります。
結果、border
の左右と下に隙間ができ、中央に表示されたように見えるのです。
回答のコードではroot
のgrid
を中央に配置しています。
その結果、border
はframe
のgrid
の上部、frame
のgrid
はframe
の上部、frame
はroot
のgrid
の上部、root
のgrid
はroot
の中央部に表示され、それぞれgrid
のサイズは子要素のサイズに合わせられますのでborder
が中央に表示されたように見えるのです。
以上、一部わかりにくかったかもしれませんが、お役に立てれば幸いです。
さて、ご質問の「Frame.py を起動した際に、radio.pyを表示させたい」というのは「radio.py
にTk関係のコードを集約し、frame.py
から呼び出したい」ということでしょうか。
それとも「2つのTkアプリケーションを同時に起動したい」ということでしょうか。
ちょっとわからなかったので、それぞれ回答します。
frame.py
からradio.py
を呼び出す
これは単純で、radio.py
のコードを関数にしてframe.py
でインポートし、適宜関数を呼んであげればOKです。
その際、radio.py
の関数にroot
を作って渡したほうがroot.mainloop()
まで関数にするよりは再利用性が高まると思います。
コードはこんな感じです。
frame.py
from tkinter import *
from tkinter import ttk
import radio # radio.pyをインポート
root = Tk()
root.title('Frame Test')
radio.frame(root) # radio.pyの関数にrootを渡してあげる
root.mainloop()
radio.py
from tkinter import *
from tkinter import ttk
def button1_clicked():
print('v1 = %s' % v1.get())
quit()
def rb_clicked():
print('v1 = %s' % v1.get())
def create(root):
# Frame
frame1 = ttk.Frame(root,padding=10)
frame1.grid()
# ...いろいろつくる...
2つのTkアプリケーションを同時に起動する
Tkは基本的に1つプロセス内では1つのTkアプリケーションしか起動できないので、これはちょっと面倒になります。
いくつか方法はありますが、一番単純なのはサブプロセスを2つ起動してその中でTkアプリケーションをそれぞれ起動する方法でしょう。
サブプロセスを2つ同時に起動するにはmultiprocessing
モジュールを使います。
multiprocessing --- プロセスベースの並列処理 ― Python 3.10.0b2 ドキュメント
frame.py
from tkinter import *
from tkinter import ttk
import multiprocessing as mp
import radio # radio.pyをインポート
def frame():
root = Tk()
root.title('Frame Test')
frame1 = ttk.Frame(
root,
height=200,
width=300,
relief='sunken',
borderwidth=5)
frame1.grid()
root.mainloop()
frame_p = mp.Process(target=frame) # frame用のプロセスを作る
radio_p = mp.Process(target=radio.main) # radio用のプロセスを作る
frame_p.start() # frame用のプロセスを起動する
radio_p.start() # radio用のプロセスを起動する
radio.py
from tkinter import *
from tkinter import ttk
def button1_clicked():
print('v1 = %s' % v1.get())
quit()
def rb_clicked():
print('v1 = %s' % v1.get())
def main():
root = Tk()
root.title('Radiobutton 1')
# Frame
frame1 = ttk.Frame(root,padding=10)
frame1.grid()
# ...いろいろつくる...
root.mainloop()
以上、お役に立てれば幸いです。
正直、discord.pyには詳しくありませんが、調べてみるとDMでも基本は普通のコマンドbotと変わらないようです。
ただしDMの場合、ctx.message.guild
はNone
になってしまうそうなので、事前にguild
とrole
を取得しておきましょう。
また、DMChannel
からのメッセージの場合、context.message.author
はMember
ではなくUser
となります。
Member.add_roles()
を使うためにはguild.get_member(context.message.author.id)
で改めて対応するMember
オブジェクトを取得する必要があります。
そして、guild.get_member()
を使用するにはIntents
というオブジェクトを使ってオプションを設定してあげる必要があります。
以下のコードではトークンや合言葉など見られてはまずいものを環境変数から読み込むようにしていますので、HerokuのConfig Varsに適宜設定するか書き換えてください。
【追記】
add_role()
の2つ目以降の引数に?r
の引数が渡されるので、いくつ渡されてもいいように可変引数とし、引数がなかったり引数に渡されたフレーズが間違っていれば「合言葉が間違っています」と表示するようにしました。
import discord
from discord.ext.commands import Bot
import os
import traceback
TOKEN = os.getenv('DISCORD_BOT_TOKEN')
GUILD_ID = int(os.getenv('DISCORD_BOT_GUILD_ID'))
ROLE_ID = int(os.getenv('DISCORD_BOT_ROLE_ID'))
WORD = os.getenv('DISCORD_BOT_WORD')
intents = discord.Intents.default()
intents.members = True
bot = Bot(command_prefix='?', intents=intents)
guild = None
role = None
@bot.event
async def on_ready():
global guild
global role
guild = bot.get_guild(GUILD_ID)
role = guild.get_role(ROLE_ID)
@bot.event
async def on_command_error(ctx, error):
orig_error = getattr(error, "original", error)
error_msg = ''.join(traceback.TracebackException.from_exception(orig_error).format())
await ctx.send(error_msg)
def is_DM(message):
return isinstance(message.channel, discord.DMChannel)
@bot.command(name='r')
async def add_role(ctx, *args):
"""DM経由かつ合言葉が合っていれば役職を付与"""
# 「?r あああ いいい」 → add_role(ctx, ['あああ', 'いいい']) → 'あああ いいい'
# 「?r」 → add_role(ctx, []) → ''
word = ' '.join(args)
if role is not None and is_DM(ctx.message) and word == WORD:
user = guild.get_member(ctx.message.author.id)
await ctx.send("役職を付与しました。")
await user.add_roles(role)
else:
await ctx.send('合言葉が間違っています。')
bot.run(TOKEN)
Botの権限も重要です。
Discord Developer PotalでBotをサーバに登録するためのURLを生成するときにBotの権限を指定します。
Manage RolesやSend Messagesが必要になります(とりあえず全部与えて試していたので、もしかしたら他にも必要な権限があるかもしれません)。
同時に、2つあるインテントの設定もオンにしてください。
詳しくは以下の質問の回答が画像付きなのでおすすめです。
Discord - How to give my bot permissions. [Javascript] - Stack Overflow
その上で、サーバーの設定画面でBot用の権限(自動で作成されます)が他の権限よりも上に来るように設定しましょう。
これをしないと一部のユーザに対して操作できなくなったりするそうです。
参考:
- Discord Bot 最速チュートリアル【Python&Heroku&GitHub】 - Qiita
- python - Permission error for discord.py bot despite having admin permissions - Stack Overflow
- discord.py入門(1) - Qiita
- discord.ext.commands -- ボットコマンドのフレームワーク
以下、少し見にくいかもしれませんが、動作した環境の各種設定です。
権限はサーバの設定から変更することはできず、Botを導入するためのURLを生成するときにしか指定できませんので、変更したい場合は一度Botをサーバから削除して導入し直す必要があるようです。
Botの削除は「サーバの設定→Integrations→Bot名→Delete Integration」で可能です。
以上、お役に立てれば幸いです
yama[i][j]
はchar
ですので、printf()
のフォーマット指定子は%c
を使います。
参考:フォーマット指定子一覧
for(i = 0;i < a;i++){
for(j = 0;j < b;j++){
printf("%c", yama[i][j]);
}
printf("\n");
}
ただ、上記の方法はprintf()
を無駄に呼びすぎです。
yama[i]
の末尾にNull文字\0
をつけて文字列にし、%s
で表示するとよいでしょう。
for(i = 0;i < a;i++){
for(j = 0;j < b;j++){
yama[i][j] = 'X';
}
yama[i][j+1] = '\0'; // 末尾にNull文字を追加して文字列にする
}
for(i = 0;i < a;i++){
printf("%s\n", yama[i]);
}
一応、j+1
がMAX2
を超えないよう注意してください。
ご参考まで。
どのライブラリを使われているかわかりませんが、コードから察するにdiscord.js
でしょうか。
であれば、message.react('絵文字')
でできます。
Message ― discord.jsのドキュメントより以下引用します。
message.react('🤔')
.then(console.log)
.catch(console.error);
// カスタム絵文字を使う場合は以下
message.react(message.guild.emojis.cache.get('123456789012345678'))
.then(console.log)
.catch(console.error);
追記
メッセージが作成されたときにそのメッセージがbotのものならリアクションをつければOKではないでしょうか。
client.on("messageCreate", async message => {
if (message.author.bot) {
message.react('🤔');
return;
}
/* ...その他いろいろやる */
}
自分のメッセージだけにつけたいなら以下です。
if (message.author.id === client.user.id) { /* ... */ }
canvasで表示した画像を中央表示の状態で、inputのrangeを使って拡大・縮小したい。 | teratail
まず、Canvasで画像を拡大縮小する方法についてですが、drawImage()
だけでできます。
/* drawImage(Image, コピー元 X, コピー元 Y, コピー元 Width, コピー元 Height,
* コピー先 X, コピー先 Y, コピー先 Width, コピー先 Height);
*/
context.drawImage(img, 0, 0, img.width, img.height,
0, 0, img.width * scale, img.height * scale);
その上で、画像の描画位置を中央にすればよいので、以下のようになります。
ご質問のコードにある「canvasサイズ-画像サイズ/2で中央に表示」と同じです。
// スライダーが動いたら拡大・縮小して再描画する
slider.addEventListener('input', e => {
// 一旦クリア
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 倍率変更
const scale = Number(e.target.value);
// 再描画
ctx.drawImage(img, 0, 0, img.width, img.height,
(canvas.width - img.width * scale) / 2,
(canvas.height - img.height * scale) / 2,
img.width * scale, img.height * scale);
});
jsonの特定の値を配列で格納する処理をスマートに書きたい | teratail
mapとdestructuringを使うのはいかがでしょう。
const users = json.values.map(({ userId }) => userId);
const counts = json.values.map(({ count }) => count);
細かいことですが、users
よりもuserIds
の方が適切かな、と思います。
ご参考まで。
追記
なぜ上記のコードになるのか、一応書いておきます。
const users = [];
json.values.forEach(value => {
users.push(value.userId);
})
まず、forEach
をmap
に書き換えます。
map
はある配列の要素を順番に取り出し、関数を適用した結果の配列を作ります。
やっていることは上のコードと同じでして、json.values
から要素を1つ({ userId: 120, count: 0 }
)順に取り出して「なにかして」その結果を配列にします。
const users = json.values.map(なにかする関数);
この「なにかする関数」のところが「{ userId: 120, count: 0 }
からuserId
の値をとってくる」という関数であればいいわけです。
つまり、こうなります。
const users = json.values.map(value => value.userId);
ここで、JavaScriptには分割代入という機能があります。
const value = { userId: 120, count: 0 };
const { userId, count } = value;
console.log(userId); // 120
console.log(count); // 0
これは関数の引数でも使えるので、「{ userId: 120, count: 0 }
からuserId
の値をとってくる」関数はこうなります。
const getUserIdOf = ({ userId }) => userId;
const value = { userId: 120, count: 0 };
console.log(userIdOf(value)); // 120
あとはこれらを組み合わせれば、冒頭の回答コードになります。
filter
もforEach
も同じようなものです。「なにかをする」関数の部分がちょっと変わるだけです。
でもとても便利なので、使えるようになると読みやすいコードが書けるようになると思います。
幾分慣れの部分がありますので、頑張ってください!
[TypeScript]複数の型を組み合わせて定義した型で、Property 'xxxx' does not exist on typeが発生する | teratail
判別可能なUnion型とユーザ定義のType Guardを組み合わせましょう。
型チェックやインテリセンスも効くようになり便利です。
判別可能なUnion型 - TypeScript Deep Dive 日本語版
interface Sample1 {
kind: 'Sample1'; // これで判別する
id: string;
name: string;
}
interface Sample2 {
kind: 'Sample2'; // これで判別する
id: string;
gender: string;
}
type Sample1and2 = Sample1 | Sample2
// ユーザ定義のType Guard
function isSample1(x: Sample1and2): x is Sample1 {
return x.kind === 'Sample1'
}
// ユーザ定義のType Guard
function isSample2(x: Sample1and2): x is Sample2 {
return x.kind === 'Sample2'
}
const sampleFunc = ({
sample
}: {
sample: Sample1and2
}) => {
if (isSample1(sample)) {
console.log(sample.id, sample.name);
} else {
console.log(sample.id, sample.gender);
}
/* switch-caseでもOK */
switch (sample.kind) {
case 'Sample1':
console.log(sample.id, sample.name);
break;
case 'Sample2':
console.log(sample.id, sample.gender);
break;
default:
// これを書いておくとSample1and2に型を足したときにここでエラーが出るようになり、
// caseを増やすのを忘れにくくなります。
const _exhaustiveCheck: never = sample;
}
}
別解としてas
でキャストすることもできますが、おすすめしません。
以上、ご参考になれば幸いです。
GASのUrlFetchAppのGETメソッドでのパラメータの渡し方 | teratail
Class UrlFetchApp | Apps Script | Google Developpers
管見の限りでは見つかりませんでした。
代わりにこんな感じでどうでしょうか。
function urlOf(url, params) {
return `${url}?${Object.entries(params).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join('&')}`;
}
UrlFetchApp.fetch(urlOf("https://www.google.co.jp/search", { q: 'fetch やり方' }))
reactでuseEffectでREST APIを叩いて得たデータをpropsとして渡したい | teratail
子コンポーネントのuseEffect
の実行は子コンポーネントが初期化された時点で起こります。
するとまだ親コンポーネント内でのfetcher()
が終わっていないため、初期値の"takeshi"
がprops.name
に渡されて子コンポーネントのname
にセットされ、その後props.name
が変更されてもuseEffect(..., [])
なので実行されず子コンポーネントのname
が初期値のままになっているのだと思います。
解決策としてはuseEffect()
の第2引数にprops.name
を追記するか……
//Child.tsx
const Parent: React.FC = (props) => {
const [name, setName] = useState('takeshi')
useEffect(() => {
setName(props.name)
}, [props.name]) // 依存先にprops.nameを追加
return (
<p>{name}</p> //ここではtakeshi
)
}
子コンポーネントでname
というStateを用意せずにprops.name
を使うかすればよいかと。
//Child.tsx
const Parent: React.FC = (props) => (
<p>{props.name}</p> // 単純にprops.nameを使う
)
個人的には子コンポーネント内でStateを持つと同じ値を2つのコンポーネントで同時に状態管理するといういびつな形になってしまうので、状態管理は親コンポーネントに任せて子コンポーネントは値を使うだけの2つ目の方法がおすすめです。
Discord.jsでメッセージにキーワードが含まれている場合、既定の候補の中からランダムでメッセージを送信する | teratail
ご質問に書かれている情報が乏しく、正しく意図を読み取れているかわかりませんが、こういう感じでどうでしょうか。
キーワードをいくつか指定できるように、Array.prototype.some()
とString.prototype.includes()
を組み合わせます。
そして、引数のうち1つをランダムに返すoneOf()
を定義しました。
トークンは環境変数APP_TOKEN
から読み込むようにしてあります。
const { Client, Intents } = require('discord.js');
const client = new Client({ intents: Object.keys(Intents.FLAGS) });
/* 引数のうち1つをランダムに返す */
function oneOf(fst, ...rest) {
const xs = [fst, ...rest];
const i = Math.floor(Math.random() * xs.length);
return xs[i];
}
client.on('messageCreate', async message => {
if (message?.author?.bot) {
// 無限ループを避けるため、Botのメッセージは無視する
return;
}
const msg = message.content ?? '';
if (['こんばんは', 'こんばんわ'].some(s => msg.includes(s))) {
await message.channel.send(oneOf('こんばんは〜', 'ばんわ', 'こん!'));
}
});
client.login(process.env.APP_TOKEN)
GAS スプレッドシートの文字列を時間として取得してカレンダーにエクスポートしたい | teratail
他の回答者の回答も参考になる。
Date.prototype.setHours()
やDate.prototype.setMinutes()
は時・分・秒などそれぞれの整数値を引数に指定します。
13:00
のような文字列だとうまくいかないので、事前にパースするとよいでしょう。
設定するだけならDate.prototype.setHours()
で時・分・秒・ミリ秒まで一括で指定できます。
Date.prototype.setHours() - JavaScript | MDN
/* '13:00'→[13, 0]にする関数 */
function parseHours(hours) {
return hours.split(':').map(v => Number(v));
}
/* ...省略... */
var startDate = new Date(day);
startDate.setHours(...parseHours(startTime));
Discord.jsでコマンドごとにファイルを分けて実行する | teratail
単純にファイルを分けたいだけなら、client.on(〜)
の部分を関数にして呼び出せばよいと思います。
// main.js
const Discord = require('discord.js')
const on_message = require('./on_message.js')
const client = new Discord.Client({ intents: [Discord.Intents.FLAGS.GUILDS, Discord.Intents.FLAGS.GUILD_MESSAGES] });
const prefix = "!";
on_message(client)
client.login('Botのトークン')
// on_message.js
function on_message(client) {
client.on('message', message => {
if (message.content === `${prefix}ping`) {
message.channel.send('Pong.');
} else if (message.content === `${prefix}beep`) {
message.channel.send('Boop.');
}
});
}
module.exports = on_message
ただ、大量にある場合は以下のようにイベントの配列を作った方が管理しやすいかなと思います。
// main.js
const Discord = require('discord.js')
const events = require('./events.js')
const client = new Discord.Client({ intents: [Discord.Intents.FLAGS.GUILDS, Discord.Intents.FLAGS.GUILD_MESSAGES] });
const prefix = "!";
// eventsを全てclientに登録
events.forEach(({name, handler}) => client.on(name, handler));
client.login('Botのトークン')
// events.js
// イベント
const events = [
require('./on_message.js'),
]
module.exports = events
// on_message.js
const name = 'message'
const handler = message => {
if (message.content === `${prefix}ping`) {
message.channel.send('Pong.');
} else if (message.content === `${prefix}beep`) {
message.channel.send('Boop.');
}
}
module.exports = {name, handler}
python:スクレイピングで特定のボタンがあるときのみ、該当箇所をクリックする方法 | teratail
複数の要素を取得するには、find_elements()
を使います。
特定のボタンがあるかどうかは返値が空配列かどうかを見ればわかりますし、for
を使えば空配列の場合は実行されません。
from selenium import webdriver
from selenium.webdriver.common.by import By
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
driver.get('取得したいサイトのURL')
links = driver.find_elements(By.CSS_SELECTOR, "a[target='QD']")
for link in links:
link.click()
# その他色々する
find_element()
などで1つづつ取得する時はNoSuchElementException
が発生したかどうかを確認すれば要素があるかわかります。
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
def find(driver, selector):
try:
return driver.find_element(By.CSS_SELECTOR, selector)
except NoSuchElementException:
return None
link = find(driver, 'a[target="QD"]')
if link is not None:
link.click()
# その他色々する
4. Locating Elements - Selenium Python Binding 2 documentation
Discord.jsでevalコマンドを実装したい(危険を承知で) | teratail
まず、再三考えたことでしょうが、eval
ではなくFunction
やJS-Interpreterといった他の方法で実現できないか今一度よく検討してみてください。
eval() - JavaScript | MDN - より安全なFunction
を使う方法などが紹介されています。
絶対にevalを使うな! - Discord.js Japan User Group - evalの代替ライブラリなどが載っています。
その上で、どうしてもeval
したいという場合は、以下が参考になるかもしれません。
JavaScriptを実行するサーバを用意して実行したい文字列を送信し、実行結果を返すことでeval
を避ける方法もあります。その場合はまた別のセキュリティリスクがありますが。
どのような目的でeval
されたいのかを書いていただければ具体的な回答を得られるかもしれません。
私はdiscord.jsでeval
したことがなく、自分がeval
を使ってコードを書いてもどなたかに使ってもらえるほど安全なものになるとは思えないので、このような回答になってしまいます。すみません。
ご参考まで。
for line in f
とあるので、for
の中身はf
の行数分、実行されます。
そのとき、dt = ast.literal_eval(line)
と結果をdt
に代入していますが、この行が実行される度にdt
に代入しているため、最後の結果しかdt
に残りません。
for
のイメージはこんな感じです。
xs = ['a', 'b', 'c']
for x in xs:
di = x
print(di)
# 以下と同じ
x = xs[0]
di = x
x = xs[1]
di = x
x = xs[2]
di = x
print(di)
そのため、意図した結果を取得するにはfor
の中にprint()
を入れて毎回print()
するか、結果を保持する変数を作ってfor
内が実行される度にそこに追加していくかする必要があります。
# ① 毎回 print()
for line in f:
di = ast.literal_eval(line)
print(di['eval_loss']) # 毎回出力するようにする
# ② 一旦リストに保存
results = []
for line in f:
di = ast.literal_eval(line)
results.append(di['eval_loss'])
print(results) # [0.6871868968009949, 0.6824596524238586, ...]
個人的には内包表記をおすすめします(やっていることは上の②のコードと同じで、書き方が違うだけです)。
results = [ast.literal_eval(line) for line in f]
print(di['eval_loss'] for di in results)
# または
print(ast.literal_eval(line)['eval_loss'] for line in f)
javascriptでsrc内に変数を用いたい | teratail
【追記】
<noscript>
について、「<noscript>
はJavaScriptが無効な環境で表示されるので、img
を追加するのは無意味ではないか」とご指摘をいただきました。
そのとおりです。コードと説明を修正しました。
<script src="'https://example.com/1/?code='+ hoge" id="aaa"></script>
はHTMLであり、"'https://example.com/1/?code='+ hoge"
もまたHTMLの一部分です。JavaScriptとして実行されるわけではありません。
ご質問にある参考文献はVueというライブラリを用いてHTMLを動的に生成しているのでこのようなことができますが、ご質問から察するにgara-pagosuさんはそういったライブラリを使っていないのではないかと思います。
その場合は、以下のようにJavaScriptで動的に<script>
要素を作ってドキュメントに追加すれば読み込むことができます。
スクリプトを動的に読み込む方法 | JavaScript プログラミング解説
img
タグについては<noscript></noscript>
内の要素をJavaScriptでは操作できないので(JavaScriptが無効の環境向けですからね……)、サーバーサイドでHTMLを生成するなどの方法をとりましょう。
<script>
var hoge = "abc";
// script要素を作る関数
function createScript(src, klass) {
var script = document.createElement("script"); // script要素を作る
srcipt.classList.add(klass); // idではなくclassを追加(下記の説明を参照)
script.src = src; // srcを設定
return script;
}
// ドキュメントが完全に読み込まれてから
document.addEventListener('load', () => {
// script要素を作ってbodyに追加
var s1 = createScript('https://example.com/1/?code=' + hoge, "aaa");
document.body.appendChild(s1);
var s2 = createScript('https://example.com/2/?code=' + hoge, "aaa");
document.body.appendChild(s2);
});
</script>
なお、var hoge = abc;
のabc
は変数名ではなく文字列でしょうから、"abc"
に修正しました。
また、HTMLではid
属性はドキュメント内で一意でなければなりません。言い換えると、ドキュメント内で同じid
は2つの要素につけることができないのです。そのため、id="aaa"
はclass="aaa"
となるよう変更しました。
クライアントサイドでスクリプトを動的に読み込む方法を書いておいて何なんですが、他の方も回答されているように今回のケースではサーバーサイドでHTMLを動的に生成する方法がよいのではないかと思います。
ご参考まで。
git push origin masterの不明な挙動 | teratail
1. パスワードを入力しているのに表示されない
これは正常な動作です。
「ショルダーハッキング」という「パスワードを入力しているところを肩越しに見て覚えることでパスワードを盗み出す」方法に対する対策として、入力した文字が表示されないようになっているのです(ATMに後ろを見る鏡がついているのもこのハッキング方法に対する対策です)。
そのため、パスワードを入力してEnterキーを押せば、表示はされませんがちゃんと入力できています。
sudo
など、他のコマンドでも同じようになっていることが多いです。
git push
するには
2. GitHubにはパスワードによるログインはできません。
SSH接続することをおすすめします。
以下にやり方が書いてあります。
GitHubでssh接続する手順~公開鍵・秘密鍵の生成から~ - Qiita
【追記】
環境情報を見落としておりました。
Windows 10の場合はこちらが参考になると思います。
失礼しました。
【初心者向け】GitHubにSSH接続する設定方法 for Windows 10 | Techs Report
基本的な手順は
- 手元のPCでSSH Key(パスワードの代わり)を生成する
- 公開鍵と秘密鍵が出来るので、公開鍵をGitHubに登録する
だけです。
ただし場合によっては追加でいくつか設定する必要があります(上記の記事に書かれています)。
上記の記事をよく読んで、試してみて出来なければまた質問してください。
SSH接続をすると、Gitを使ってGitHubアカウントにログインしてきたPCがちゃんとそのGitHubアカウントの所有者のものかをGitHubが確認することができます。
と同時に、Gitは事前に設定してあるSSHの情報を使えば、git push
の度に一々パスワードやアカウント名を聞かなくて済みます。
毎回入力するパスワードの代わりに事前にSSHキーを設定しておいて、それを使ってGitHubにログインするわけです。
この設定はPC毎に行う必要はありますが、1度設定してしまえばアカウントやパスワードの入力を省略できてセキュアなためおすすめ、というわけです。
3. GitとGitHub
余談ですが、git
コマンドとGitHubの関係をおさらいしておきます。
Gitはバージョン管理システムの一種で、git
コマンドを用いてファイルやフォルダの変更内容を記録しておくことができます。
この記録は「リポジトリ」単位で行われます。
また、Gitは「リモートリポジトリ」と呼ばれるネット上にあるリポジトリと「ローカルリポジトリ」と呼ばれる手元のPCにあるリポジトリを同期する機能があります。
GitHubはGitのリモートリポジトリをホストできるサイトで、リポジトリの変更内容を見たり、編集したりできます。
Gitリポジトリ専用のGoogle Driveのようなものですね。
同じようなサービスとしてGitHub以外にもGitLabやBitBucketなどがあります。
GitHubを含め、これらホスティングサービスはGitとは独立したプロジェクトでして、Gitはそういったサービスなしでも使うことができます。
そして、つい先日までは、GitのリモートリポジトリにGitHub上のリポジトリを指定している場合、GitHubのユーザー名とパスワードを入力してログインすることで同期できるようになっていました。
しかし、セキュリティの観点からパスワードを使ったログインが廃止され、従来からあったSSHキーを登録してSSH接続する方法か、GitHub上でアクセストークンを発行しそれを使ってログインする方法でしかGitHubにログイン出来ないようになりました。
そのため、Gitがユーザーにパスワードを入力してもらいそれを使ってログインしようとすると、GitHubから「パスワードによるログインが廃止された」旨のメッセージが送り返され、ユーザーに該当のエラーが表示されるのです。
軽く調べた限りではありますが、以下の情報がありました。
-
GitLab自体のIssueに同様の要望がありました。
ただ、1年前から存在しOpenのままなので、残念ながらGitLabの機能としては実装されていないと見るべきかもしれません。
Search: attachments. (#214604) · Issues - GitLab.org -
GitLab APIのNotes APIでProjectごとのIssue Note(Issueのコメントに相当)を取得すると
attachments
プロパティがあるようなので、使えるかもしれません。自分でプログラムを書かねばなりませんが……
List project issue notes - Notes API | GitLab
以上、ご参考まで。
JavaScript 変数内の特定のタグを除去する | teratail
正規表現を使ってString.prototype.replace
するのはいかがでしょう。
正規表現 - JavaScript | MDN
String.prototype.replace() - JavaScript | MDN
alert(s.replace(/<span.*>.*<\/span>/, ''));
一部を残したいのであれば正規表現のキャプチャ機能を使いましょう。
alert(s.replace(/<span.*>(.*)<\/span>/, "$1")); // ()で囲んだ部分が$1に入る
指定した時間で繰り返しの処理を止めたい | teratail
【追記】
clock_gettime()
を使ったコードに変更しました。
clock_gettime()
はtimespec
型の値を返し、timespec
型は秒とナノ秒の情報が入った構造体です。
clock_gettime(CLOCK_MONOTONIC, ×pec型の変数)
とすると単調増加の値が得られます。
計測を始めた時点の値と現在の値の差が10秒以下の間処理を繰り返すプログラムを書けばHIG4TOさんのやりたいことが実現できるのではないでしょうか。
今回はナノ秒のオーダーは必要ないと思われますので、単純に秒のみを比較します。
処理を繰り返すときは定期的にsleep()
のような関数を呼び出さないとハングアップしてしまいますので注意です。
HIG4TOさんの環境が不明ですのでここではunistd.h
のusleep()
を使っていますが、Windowsなどの場合は代替となる関数(windows.h
のSleep()
とか)をググってみてください。
時間情報の取得 clock_gettime() - 時間の扱い - 碧色工房
#include <time.h>
#include <unistd.h>
int main() {
struct timespec start, current;
time_t diff = 0;
clock_gettime(CLOCK_MONOTONIC, &start);
while (diff < 10) {
usleep(0.5 * 1000000); // 0.5秒待つ
// その他いろいろやる
clock_gettime(CLOCK_MONOTONIC, ¤t);
diff = current.tv_sec - start.tv_sec;
}
return 0;
}
Python スクレイピング件数が複数にまたがるときの条件分岐 | teratail
2ページ目のURLを見てみるとhttps://el.e-shops.jp/local/jb/6008/jn/6000523/cn/23109/2.html
のように末尾に2.html
が付いています。別の区の3ページ目も確認すると末尾が3.html
でした。
ということはbase_url
をhttps://el.e-shops.jp/local/jb/6008/jn/6000523/cn/23109/
とすると、2ページ目はbase_url + '2.html'
、3ページ目はbase_url + '3.html'
……となっているわけです。
そして、最後のページの次のページ(例えばhttps://el.e-shops.jp/local/jb/6008/jn/6000523/cn/23109/3.html
)を見てみると、.list-tel-shop
という要素がないページが表示されます。
ここまでのことから、順番にURLを変えてアクセスしていって.list_tel_shop
が取得できなくなったらその区はおわり、という判断の仕方ができます。
コードに落とし込むと、こんな感じでしょうか。
import requests
import re
from bs4 import BeautifulSoup
def get_shops_at_page(base_url, n):
"""ある区のn番目のページにあるすべてのlist_tel_shopを返す"""
url = f"{base_url}{str(n)}.html" if n > 1 else base_url
res = requests.get(url)
soup = BeautifulSoup(res.text, 'html.parser')
return soup.find_all('div', attrs={'class': 'list_tel_shop'})
def get_shops(base_url):
"""ある区のすべてのlist_tel_shopを返す
返値は [{'name': '...', 'address': '...', 'tel': '...'}, {...}, ...]
"""
shops = []
n = 1
# get_shops_at()が[]を返すまでどんどん次のページの情報を取得する
while True:
shop_els = get_shops_at_page(base_url, n)
if not shop_els:
break
for shop_el in shop_els:
# 以下、shop_el.find_all()でないのは「shop_el」つまり「.list_tel_shop」に
# 「.shop_address」や「.shop_tel」といった要素が1つづつしか存在しないため
shop = {}
name = shop_el.find('a', href=re.compile("^/local/nsh/"))
if name:
shop['name'] = name.text
address = shop_el.find('p', attrs={'class': 'shop_address'})
if address:
shop['address'] = address.text
tel = shop_el.find('p', attrs={'class':'shop_tel'})
if tel:
shop['tel'] = tel.text
shops.append(shop)
n += 1
return shops
# 複数の区の情報を得るなら以下のように使う
def flatten(xs):
return list(itertools.chain.from_iterable(xs))
urls = [
'https://el.e-shops.jp/local/jb/6008/jn/6000523/cn/23109/',
]
# [ [{...}, ...], [{...}, ...], ... ]になるのでflattenして[{...}, {...}, ...]に
shops = flatten([get_shops(url) for url in urls])
get_shops()
ではshop
ごとに{'name': '...', 'address': '...', 'tel': '...'}
という辞書を作ってそのリストを返すようにしています。
name
/address
/tel
それぞれのリストがほしければ以下のようにしましょう。
names = [shop['name'] for shop in shops]
address = [shop['address'] for shop in shops]
tels = [shop['tel'] for shop in shops]
これらを一列づつ追加してもいいですが、一気にpd.Dataframe
にした方がいい気がします。
import pandas as pd
# [[shopの社名, shopの住所, shopのTEL], [...], ...]に変換
data = [[shop['name'], shop['address'], shop['tel']] for shop in shops]
df = pd.DataFrame(data, columns=['社名', '住所', 'TEL'])
xs.map(f)
は配列xs
のすべての要素に対して関数f
を適用した結果の配列を返します。
言い換えれば、xs
のすべての要素に対してf(xs[0])
, f(xs[1])
, ...と適用した結果の配列を返します。
具体的には、以下のように使います。
const xs = [0, 1, 2]
const ys = xs.map(x => x + 1) // xsのすべての要素に1を足す
// ys は [1, 2, 3]
一方、xs.slice(n)
は配列xs
のn
番目より後の要素を返します。
const xs = [0, 1, 2, 3, 4]
const ys = xs.slice(2) // xsの2番目より後の要素=3番目から最後まで
// ys は [2, 3, 4]
したがって、list.slice(0).children.map
はlist.slice(0)
が配列(中身は空[]
)なのでchildren
がundefined
になってしまい、エラーが出たのではないかと思います。
list[0].children.map
でいいのではないでしょうか。
以上の話を踏まえた上で、実現したいことはlist
の要素を2つづつ<div class="grid-inner">〜</div>
に入れるということでよろしいでしょうか。であれば、まずlist
の要素を2つづつ取り出してlist_by_2
という配列にし、その配列をArray.prototype.map
で操作していきましょう。
「配列の要素を2つづつ取り出して配列にする」ために「配列をn個づつに分割する」関数を定義します。
JSで配列をn個ずつに分割 - Qiitaのコードを使っています。
const split = (array, n) => array.reduce((a, c, i) => i % n == 0 ? [...a, [c]] : [...a.slice(0, -1), [...a[a.length - 1], c]], [])
これをlist
に適用すると、[ [{...}, {...}], [{...}, {...}], ... ]
とlist
の要素が2つづつ配列に入った配列になります。そしてlist_by_2.map(items => ...)
のitems
は[{...}, {...}]
となりますから、再びitems.map(item => ...)
とすることでitem
が{_id: ..., children: ..., name: ...}
となります。
そんな感じで書いていくと、以下のようになると思います。
// from: https://qiita.com/guttyar2213/items/46230300c5100a06198c
const split = (array, n) => array.reduce((a, c, i) => i % n == 0 ? [...a, [c]] : [...a.slice(0, -1), [...a[a.length - 1], c]], [])
const Grid = (props) => {
// list_by_2: [{...}, {...}, ...] -> [ [{...}, {...}], [{...}, {...}], ... ]
const list_by_2 = split(list, 2)
return (
<div className="grid">
{list_by_2.map(items => ( // itemsは[{...}, {...}]
<div className="grid_inner">
items.map(item => (
<div className="title">
<a href={item._id}>{item.name}</a>
</div>
<ul className="footer-category-links">
{item.children.map(({_id, name}) => ( // child => ...の代わりに ({_id, name}) => ...と分割代入しています
<li key={_id}><a href={_id}>{name}</a></li>
)}
</ul>
)
</div>
)}
</div>
)
}
discord.pyにてある特定のserverのみコマンドを使えるようにしたい | teratail
message.channel
がTextChannel
のインスタンスのとき(DMChannel
やGroupChannel
以外のサーバに属しているメッセージのとき)、TextChannel.guild
にサーバ情報がはいっているのでそれを使えば判定できます。
GUILD_ID = 'サーバのID'
@client.event
async def on_message(message):
if not isinstance(message.channel, discord.TextChannel) or message.channel.guild.id != GUILD_ID:
# 特定のサーバでなければなにもしない
return
# ... なにかする ...
特定の時刻になったらボイスチャットから切断する | teratail
require()
はできるだけファイル冒頭でする
細かいことですが、そのファイルがどんな外部モジュールに依存しているかをファイル冒頭にまとめておくと見やすいので、require()
はできるだけファイルの冒頭に書きましょう。
var
もconst
にしています。
const cron = require('node-cron')
/* ... なんやかんやあって ... */
client.on('ready', () => {
/* ... いろいろする ... */
})
client.guilds.fetch(guildID)
ではなくclient.guilds.cache.get(guildID)
client.guilds.fetch()
は引数にサーバID(Snowflake
)ではなくサーバオブジェクト(GuildResolvable
)を渡さなくてはならないので、代わりにclient.guilds.cache.get(guildID)
を使います。
cron.schedule('00 17 * * *', async () => {
const guildID = 'ギルドID'
const guild = client.guilds.cache.get(guildID);
/* ...guildを使ってなにかする... */
guild.channels.cache.filter()
はCollection
を返す
Array.prototype.filter()
と同じような関数で、返値はChannel
ではなくCollection
です。
そのため、各チャンネルのmembers
プロパティを取得するにはCollection.each()
しましょう。
const vchannels = guild.channels.cache.filter(channel => channel.type === 'voice')
vchannels.each(vchannel =>
vchannel.members.each(/* ... */)
)
VoiceChannel
から退出させる方法
ユーザをいくつか方法があり、その中でもバージョンによって動くものと動かないものがあるようです。
- ボイスチャットからユーザーを蹴る - Discord.js Japan User Group
- VoiceState.disconnect() - discord.js Documentation
- javascript - How do I disconnect a user from a voice channel in discord.js? - Stack Overflow
- javascript - Discord.Js disconnect members voice channel - Stack Overflow
member.voice.setChannel(null)
やmember.setVoiceChannel(null)
はメンバーのチャンネル情報をnull
に設定することにより、ボイスチャンネルから退出させるというものです。
一方、member.voice.disconnect()
やmember.voice.kick()
は文字通りメンバーをボイスチャンネルから退出させるために用意された関数です。
バージョンによってdisconnect()
が使える・使えない分かれるようですが、どのバージョンから使えるのかは残念ながらわかりません。kick()
は公式ドキュメントから見つけることすらできませんでしたが、ユーザ発の情報では割とありましたので、昔からある方法なのかもしれません(この辺は伝聞になってしまいますが申し訳ない)。
【追記】
hinanonさんによると「await member.voice.kick().catch(console.error)にしたら動きました」とのことです。
以下のコードもその情報に合わせて修正しました。
member.voice.disconnect('理由')
やmember.voice.kick()
はPromise
を返す 非同期関数 なので、await
で処理が終わるまで以降のコードの実行を中断します。
await
を使うにはそのコードが含まれる関数をasync
にしなければいけないので、そこも修正します。
また、細かいことですが、if
文周りでバグが入りそうなコードになっている(おそらくmember == null
のときでもconsole.log(member.id)
が実行される)ので{...}
で範囲を明確にしました。
if
やwhile
などは例え1行だとしてもif (...) {...}
にしておくと意図しない動作を防げます。
vchannel.members
もCollection
なので、forEach()
ではなくeach()
を使っています。
vchannel.members.each(async member => {
if (member) {
// disconnect()を使う方法
await member.voice.disconnect(`2時になったのでボイスチャットからキックしました(*'▽')`).catch(console.error)
// kick()を使う方法
await member.voice.kick().catch(console.error)
console.log(member.id)
}
})
channel.send()
はPromise
を返す
Promise
を返す関数は基本的にawait
して.catch()
でエラー処理するようにしましょう。
なお、await member.voice.disconnect()
するとdisconnect()
の処理が終わるまでそれ以降のコードの実行を中断するので、その後にメッセージを送る場合もsetTimeout()
でdisconnect()
の処理が終わるまで待つ必要はありません。
await member.voice.disconnect(`2時になったのでボイスチャットからキックしました(*'▽')`).catch(console.error)
/* 処理待ちは必要ない */
await channel.send(`2時になったのでボイスチャットからキックしました(*'▽')`).catch(console.error)
こんな感じでしょうか。
一応、guild
, vchannels
, channel
がnull
やundefined
, []
だった場合のエラー処理をしていませんのでご注意ください。
ご参考まで。
連想配列の不要なデータを削除しソートする方法について | teratail
質問者さんのように2つの処理に分けてforeach
する考え方で全く問題ないと思います。
ソートする方の関数がよくわからないことになっていますが……
foreach
の中でmultisort()
を呼び出すのではなく、foreach
でソート用にpriceの値のみの配列$sort_keys
を作った後にforeach
の外で1回だけmultisort()
を呼べばいいのではないでしょうか。
foreach ($data as $key => $value) {
$sort_keys[$key] = $value['price'];
}
multisort($sort_keys, SORT_ASC, $data);
個人的に配列の操作は(よほど複雑でなければ)foreach
よりarray_*()
系の関数の方がわかりやすいかなと思っているので、こう書くかなと思いました。
// priceがsoldのものを除く
$data = array_filter($data, fn($x) => $x['price'] !== 'sold');
// priceで昇順に並び替え
array_multisort(array_column($data, 'price'), SORT_ASC, $data);
画像挿入の条件分岐のコード修正をお願いします。 | teratail
本題に入る前に、細かいことで恐縮ですが、質問する時はコードをコードブロックで囲っていただければ幸いです。
詳しくは以下をご覧ください。
質問する際にMarkdownは必ず使って欲しい - Qiita
Saienn877さんのコードをみる限り、JavaScriptやHTMLの基礎がまだ十分身についていないようだと感じました。
そのため、できるだけ丁寧に説明しようとした結果、すごく長くなってしまいました。
大変恐縮ですが、ご参考になれば幸いです。
</fieldset>
対応していない</fieldset>
に対応する<fieldset>
がなかったので補うか、削除しましょう。
今回は特になにかに使っているわけではないようなので、シンプルに削除してしまってよいと思います。
<input type="text">
を<select>〜</select>
に
ご質問のコードを読むと、ユーザからの入力はある
とない
しか想定していないようです。
このように「特定の値から一つを選んでもらう」ためのHTML要素は<input type="radio">
や<select>
があります。
今回の場合は<select>
がよいのではないでしょうか。
- <input type="radio"> - HTML: HyperText Markup Language | MDN
- <select>: HTML 選択要素 - HTML: HyperText Markup Language | MDN
また、<input type="text">
のid
属性もshowMessage
だとよくわからない上、コード中で使っていないのでとりあえず削除しました。
<form name="js">
髪<br>
<select name="yourarea" autocomplete="on">
<option value="ある">ある</value>
<option value="ない">ない</value>
</select>
</form>
フォームの値の取得
JavaScriptでフォームの値を取得する方法はいくつかありますが、今回はname
属性を指定しているのでそれを使いましょう。
また、JavaScriptでは再代入できない変数(≒中身を書き換えない変数)を宣言するのにconst
を使います。
というか、できるだけconst
を使い、「const
宣言した変数に代入しようとしてるよ」という旨のエラーが出たらlet
に書き換える、くらいにした方がよいでしょう。
i
という変数名では何を表しているのか不明なので、yourarea
という名前に変えておきます。
const yourarea = document.forms.js.elements.yourarea.value;
見やすい条件分岐にする
条件分岐はswitch
でもできますが、今回はある
とない
と「未選択」だけなので、if〜else
で十分です。
JavaScriptでは文字列を"〜"
か'〜'
で囲みますので注意しましょう。
また「ある文字列と別の文字列が等しい」ということを表すには===
を使います。
ユーザが<select>
の値を未選択のときはyourarea
の値は空文字列(""
や''
)となりますので、「yourarea
の値を!
を使ってfalse
に変換できるか」をもとに判定します。
if (!yourarea) {
/* 未選択の時の処理 */
} else if (yourarea === "ある") {
/* 「ある」の時の処理 */
} else {
/* それ以外、つまり「ない」の時の処理 */
}
もしどうしてもswitch
で書きたいのであれば以下のようにすればよいでしょう。
switch (yourarea) {
case "ある":
/* 「ある」の時の処理 */
break;
case "ない":
/* 「ない」の時の処理 */
break;
default:
/* それ以外、つまり未選択の時の処理 */
break;
}
switch
の各case
について
各case
の中をみると、funcion loadImage(id) {〜}
となっています。
しかし、function() {〜}
というのは関数宣言でして、関数は宣言しただけでは実行されません。
関数を実行するには関数名(引数)
と書きます。今回ならloadImage("<canvas>要素のID")
ですね。
また、関数宣言は(基本的には)一度すれば十分ですから、tbox1()
関数の外に定義しておきましょう。
そもそもfunction tbox1( {
と文法エラーがありますので、そこも直します。
というわけで、ここまでのJavaScriptのコード部分をまとめるとこうなります。
function loadImage(id) {
/* 画像を読み込む処理 */
}
function tbox1() {
const yourarea = document.forms.js.elements.yourarea.value;
if (!yourarea) {
/* 未選択の時の処理 */
} else if (yourarea === "ある") {
/* 「ある」の時の処理 */
} else {
/* それ以外、つまり「ない」の時の処理 */
}
}
JavaScriptで画像を表示するには
Saienn877さんはCanvas APIを使われていますが、ただ画像を読み込んで表示するだけにはちょっと大げさなように思います。
「Canvas APIで画像処理をしたい」などでなければ、予め<img>
要素を用意していおいてそれを取得し、src
属性に画像のURLを指定することで画像を読み込むようにすれば十分かと。
というわけでまずは<img>
をHTMLに追加します。
検索ボタンの下に表示するようにしてみます。
単純にボタンの後に<img>
を追加すると改行されず見づらいので、ボタンの後に改行(<br>
)を追加し、その後に<img>
を追加します。
あとでJavaScriptから探しやすいよう、id
属性もつけておきます。
<input type="button" value="検索" onclick="tbox1()"><br>
<img id="result" alt="検索結果の画像">
では追加した<img>
を探して画像を読み込む処理をloadImage()
関数に書いていきます。
loadImage()
関数を読むとある
とない
のそれぞれの場合の違いは画像のURLだけなので、引数から未使用だったid
を削除し、代わりにurl
を指定するようにしました。
function loadImage(url) {
// <img>要素を探す
const img = document.getElementById("result");
if (img) {
// <img>が見つかったら、src属性にURLを指定して画像を読み込む
img.src = url;
}
}
どうしてもCanvas APIを使いたい場合も同様に、HTMLに<canvas>
を追加してloadImage()
で探します。
画像は<canvas>
とは別にメモリ上に読み込み、画像の読み込みが終わったらCanvasに描画します。
この処理はほとんど質問にあるコードと同じですね。
<input type="button" value="検索" onclick="tbox1()">
<canvas id="result"></canvas>
<script>
function loadImage(url) {
// <canvas>を探す
const canvas = document.getElementById("result");
const context = canvas?.getContext('2d'); // .? はオプショナルチェーン演算子といいます
if (canvas && context) { // canvasとcontextが取得できたら
const image = new Image(); // 画像オブジェクトを用意
image.src = url; // URLの画像を読み込む
image.addEventListener("load", () => { // () => {...} はアロー関数といいます
// 読み込みが完了したらCanvasのサイズが画像のサイズと同じになるように設定して描画
canvas.width = image.width;
canvas.height = image.height;
context.drawImage(image, 0, 0);
})
}
}
/* その他いろいろ */
</script>
各条件ごとの処理
あとはyourarea
の値にあわせてloadImage()
を呼び出すだけです。
まず、未選択の場合は「検索」ボタンが押されても何もしないようにします。
これを実現するのは簡単で、ただtbox1()
関数の処理を終えればいいだけです。
if (!yourarea) {
return; // 未選択なら何もしない
} else if (yourarea === "ある") {
/* 「ある」の時の処理 */
} else {
/* それ以外、つまり「ない」の時の処理 */
}
「ある」と「ない」のときはそれぞれURLが異なる画像を読み込むので、loadImage()
を呼び出します。
「ある」の時のURLが画像ではなくHTMLだったので、適宜変えてください。
if (!yourarea) {
return; // 未選択なら何もしない
} else if (yourarea === "ある") {
loadImage("「ある」のときの画像のURL");
} else {
loadImage("https://image.itmedia.co.jp/nl/articles/1701/21/l_miya_170121hagehair10.jpg");
}
以上、長くなってしまってすいませんでした。
コードをコピペしたり写経したり参考にしたりするときは「そのコードが何をしているのか」を(なんとなくでいいので)把握するようにすると、思い通りのプログラムを自分の力で書くことができるようになると思います。
わかりにくいところもあったかと思いますが、頑張ってみてください。
「int
型の変数に格納されている値を100
に変更」する関数とのことですが、どちらの関数も引数の型が意図したものとは違うように思います。
hundred1(int a)
は引数がint
型なので値そのものがコピーして渡されますから、書き換えられたとしても関数を抜けるとその値は保存されないので意味がないでしょう。
以下のようなコードを書いて実行すると確認できます。
#include <stdio.h>
void hundred1(int i) {
i = 100; // 引数を書き換えてみるが……
return;
}
int main() {
int a = 50;
printf("a = %d\n", a);
hundred1(a);
printf("a = %d\n", a);
return 0;
}
hundred2(int** b)
は逆にint
型のポインタのポインタとなっているため、引数の中身(int
型の値)にアクセスするには**b
と2回 デリファレンス する必要があります。
ポインタについてまだ十分な理解ができていないのかなと愚推します。
その場合は以下を読んでいろいろとコードを書いて、しっかり理解しましょう。
【C言語】ポインタを初心者向けに分かりやすく解説 - だえうホームページ
「値渡し」と「参照渡し」の話 ポインタ渡しとは? - Qiita
#include <stdio.h>
void hundred(int* i) {
*i = 100; // ポインタが指し示す先の値を変更する
return;
}
int main() {
int a = 50;
printf("a = %d\n", a);
hundred(&a); // 変数を書き換えられるようにポインタを渡す
// hundred1(a); // これだと値をコピーして渡しているので書き換えられない
printf("a = %d\n", a);
return 0;
}
コメントを参考に回答を改善しました。
みなさんありがとうございます。
他の回答者の回答も参考になる。
こういったデータ変換系の話は、一歩々々に分けて考えるとやりやすいです。
というわけで、まずは{ "node": { "description": ..., ... } }
を{ "description": ..., ... }
に変換するコードを考えます。
const edge = { "node": { "description": ..., ... } };
const node = edge["node"];
次は{ "edges": [...] }
を[...]
に変換するコードです。
const products = { "edges": [...] };
const edges = products["edges"];
上記のことから、{ "products": { "edges": [{ "node": { "description": ... } }, ...] } }
を{ "products": [{ "description": ... }, ...]
に変換するのは以下のように書けます。
const data = {
"products": {
"edges": [{
"node": {
"description": "Sleek and black",
"featuredImage": {
"id": "gid://shopify/ProductImage/15464783282345",
"originalSrc": "https://cdn.shopify.com/s/files/1/0268/1005/6873/products/bb20.jpg?v=1602116082"
},
"handle": "skirt",
// ...
},
}],
},
};
const result = {
"products": data["products"]["edges"].map(edge => edge["node"])
};
"images"
の中身も入れ子にはなっていますが、同様に処理できます。
一点、{ ...node, "image": 〜 }
としてnode["image"]
だけを書き換えていることに注意です。
で、これらを踏まえ、こんな感じでどうでしょうか。
const data = {
"products": {
"edges": [{
"node": {
"description": "Sleek and black",
"featuredImage": {
"id": "gid://shopify/ProductImage/15464783282345",
"originalSrc": "https://cdn.shopify.com/s/files/1/0268/1005/6873/products/bb20.jpg?v=1602116082"
},
"handle": "skirt",
"images": {
"edges": [{
"node": {
"id": "gid://shopify/ProductImage/15464783282345",
"originalSrc": "https://cdn.shopify.com/s/files/1/0268/1005/6873/products/bb20.jpg?v=1602116082"
},
}],
},
// ...
},
}],
},
};
const result = {
"products": data["products"]["edges"].map(
edge => edge["node"]
).map( // ここまでで{ "products": [{ "description": ... }, ...] }になっている
node => ({
...node,
"images": node["images"]["edges"].map(
edge => edge["node"]
)
})
),
}
console.log(JSON.stringify(result, null, 2));
/* result
{
"products": [{
"description": "Sleek and black",
"featuredImage": {
"id": "gid://shopify/ProductImage/15464783282345",
"originalSrc": "https://cdn.shopify.com/s/files/1/0268/1005/6873/products/bb20.jpg?v=1602116082",
},
"handle": "skirt",
"images": [{
"id": "gid://shopify/ProductImage/15464783282345",
"originalSrc": "https://cdn.shopify.com/s/files/1/0268/1005/6873/products/bb20.jpg?v=1602116082",
}],
}],
}
*/
遅刻3回で欠席1回分としてカウントするにはどうしたらいいか? | teratail
求めたい欠席
は欠席日数 + 遅刻を3回毎に1
でしたね。
遅刻を3回毎に1
というのはつまり、遅刻した日数を3で割ったときの商
です。
例えば「遅刻が4回なら4÷3=1あまり1
なので欠席1」、「遅刻が10回なら10÷3=3あまり1
なので欠席3」のように、3で割ったときの商
で求められます。
そして、Excelには商を求めるためのQUOTIENT関数があります。
以上のことから、欠席日数
と遅刻日数
がそれぞれD12
/D13
に入っているとすると、欠席
は=SUM(D12,QUOTIENT(D13,3))
となるのではないでしょうか。
いま手元にExcelがないのでコードの検証はしていませんが(申し訳ない)、「こんな風に考えるといいのではないか」という考え方の部分だけでも参考になれば幸いです。
text-align: right;
というのは「中身を行ボックスの右辺に寄せる」ことを表します。
行ボックスというのはbibiyellowさんが仰るところの「aquaライン」のことです。
left
/right
という字面にとらわれると「右辺」というのは「画面における右側」と思いがちですが、実はそうではありません。あくまで「行ボックス」の「右辺」です。
CSSには「フロー」と「書字方向」という概念があります。簡単に言えば、「要素をどの方向に詰めていくか」「文字などをどの方向から書くか」を決めるためのものです。text-align
などのプロパティはフローや書字方向に基づいて見た目の挙動が変わります。
普段はフロー方向が水平で書字方向が左書きなので「行ボックスの右辺」は「画面における右側」と一致してします。しかし今回の場合、縦書きで右書きになっているため、結果的に「行ボックスの右辺」が「画面における下側」の方向になっています。
もっとシンプルに「要素が時計回りに90度回転している」と考えてみるとわかりやすいかもしれません。
なお、縦書きにしているときはtext-align
の値をleft
/right
ではなくstart
/end
にした方が混乱しにくく、おすすめです。
ある配列の特定の要素を更新する処理はArray.prototype.map()
を使って以下のように書きます。
const update = (arr, index, value) =>
// mapに渡す関数で、i番目の要素ならvalue、それ以外はオリジナルを返すことで、配列を更新する
arr.map((v, i) => i === index ? value : v);
あるオブジェクトの特定のプロパティの値を更新する処理はスプレッド構文を使って以下のように書けます。
const updateId = (obj, newId) =>
// スプレッド構文でオブジェクトの中身を展開し、キーが"id"のプロパティの値はnewIdにすることで更新する
({ ...obj, id: newId });
キー名も引数で指定したいときはこうです。
const update = (obj, key, value) =>
// スプレッド構文でオブジェクトの中身を展開し、キーがkeyのプロパティの値はvalueにすることで更新する
({ ...obj, [key]: value });
よって、配列の中のi
番目のオブジェクトのchecked
プロパティを更新する処理はこう書きます。
const update = (arr, index, value = true) =>
arr.map((item, i) => ({
...item,
checked: (i === index) ? value : item.checked,
}));
const data = [{
id: "a",
checked: false,
}, {
id: "b",
checked: false,
}];
const b_checked = update(data, 1);
/*
b_checked = [{
id: "a",
checked: false,
}, {
id: "b",
checked: true, // 2番目のオブジェクトのcheckedプロパティが更新される
}];
*/
というわけで、これらを踏まえて考えてみると、以下のようになるのではないでしょうか。
parent_id
とchild_id
を指定して更新するパターンと、配列のインデックスを指定して更新するパターンを作ってみました。
// parent_idとchild_idを指定して更新
const updateCheckById = (data, parentId, childId, value = true) =>
data.map(parent => ({
...parent,
state: parent.state.map(child => ({
...child,
checked: (parent.parent_id === parentId && child.child_id === childId) ? value : child.checked,
})),
}));
// インデックスを指定して更新
const updateCheckByIndex = (data, parentIndex, childIndex, value = true) =>
data.map((parent, parent_index) => ({
...parent,
state: parent.state.map((child, child_index) => ({
...child,
checked: (parent_index === parentIndex && child_index === childIndex) ? value : child.checked,
})),
}));
以上、お役に立てれば幸いです。